搜索词>>沁园净水器 耗时0.0120
  • 沁园净水器401A参考价格_沁园401A价格

    沁园净水器401A参考价格,沁园401A价格,沁园本身也是国内做净水器不错的厂商沁园净水器401A参考价格,沁园401A价格,沁园本身也是国内做净水器不错的厂商。上市年份:2012价格参考:¥3500是否推荐:不推荐目前该款有点过时,很多地方已经下架,部分商超再线下活动的时候推荐。都2020年了,买这个就相当于买了个32寸的CRT方脑壳电视机。写在最后不要相信那些商场&超市虚高价格然后打折送礼品。还是老老实实买个靠谱点的产品。
  • Java编程中spring boot项目动态添加拦截器Interceptor

    Java编程中spring boot项目动态添加拦截器InterceptorJava编程中spring boot项目动态添加拦截器Interceptor<br /> <br /> 1.自定义一个接口继承HandlerInterceptor接口 <pre> <code class="language-java"> import org.springframework.web.servlet.HandlerInterceptor; /** * url 拦截器 * * @author leftso * */ public interface UrlInterceptor extends HandlerInterceptor { String[] pathPatterns(); } </code></pre> 2.写一个配置类,动态添加自定义接口实现类实例的拦截器到容器中 <pre> <code class="language-java"> import java.util.Iterator; import java.util.Map; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /** * 添加自定义的拦截器 * * @author * */ @Configuration public class MyMvcConfigurerAdapter extends WebMvcConfigurerAdapter { @Autowired SpringUtils springUtils; @Override public void addInterceptors(InterceptorRegistry registry) { super.addInterceptors(registry); @SuppressWarnings("static-access") Map<String, UrlInterceptor> urlInterceptors = springUtils.applicationContext .getBeansOfType(UrlInterceptor.class); Set<String> keys = urlInterceptors.keySet(); Iterator<String> it = keys.iterator(); while (it.hasNext()) { String key = it.next(); UrlInterceptor urlInterceptor=urlInterceptors.get(key); registry.addInterceptor(urlInterceptor).addPathPatterns(urlInterceptor.pathPatterns()); } } } </code></pre> (获取spring的容器请参照本站另外一篇博客<a href="http://www.leftso.com/blog/118.html" target="_blank">http://www.leftso.com/blog/118.html</a>)<br /> 3.自己定义一个拦截器类,实现上面自己自定义的拦截接口 <pre> <code class="language-java"> import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.ModelAndView; @Component public class MyInterceptor implements UrlInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Before...."); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Doing...."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("After...."); } @Override public String[] pathPatterns() { return new String[] { "/**" }; } } </code></pre> 到这里就已经完成动态注入拦截器到容器中了。其他业务的拦截器只要实现自定义的拦截接口并用注解注解为spring组件就可以自动的被添加到容器中,不用每一次都去注册拦截器到spring容器中
  • Linux后台下载工具(器)transmission 使用详解

    Linux后台下载工具(器)transmission 类似迅雷使用详解,transmission 是一款支持绝大多数Linux系统的下载工具,采用web进行管理。可以通过web添加bt下载文件下载任务也可以直接指定下载url进行下载,一切皆在web中完成,这对Linux来说简直是一个下载神器啊。transmission简述Linux后台下载工具(器)transmission 使用详解,transmission 是一款支持绝大多数Linux系统的下载工具,采用web进行管理。可以通过web添加bt下载文件下载任务也可以直接指定下载url进行下载,一切皆在web中完成,这对Linux来说简直是一个下载神器啊。
  • Spring Security 配置多个Authentication Providers认证器

    Spring Security 配置多个Authentication Providers认证器Spring Security 配置多个Authentication Providers认证器 <h2><strong>1.概述</strong></h2> 在这篇快速文章中,我们将重点介绍如何使用多种机制在Spring Security中对用户进行身份验证。<br /> 我们将通过配置多个身份验证提供程序来完成此操作<br />   <h2><strong>2. Authentication Providers</strong></h2> AuthenticationProvider是从特定存储库(如数据库,LDAP,自定义第三方来源等)获取用户信息的抽象概念。 它使用获取的用户信息来验证提供的凭证。<br /> <br /> 简而言之,当定义多个身份验证提供程序时,提供程序将按其声明的顺序进行查询。<br /> <br /> 为了快速演示,我们将配置两个身份验证提供程序 - 一个定制身份验证提供程序和一个内存身份验证提供程序 <h2><strong>3. Maven 依赖</strong></h2> 我们首先在我们的Web应用程序中添加必要的Spring Security依赖项: <pre> <code class="language-xml"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency></code></pre> 没有Spring Boot: <pre> <code class="language-xml"><dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>5.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.0.4.RELEASE</version> </dependency></code></pre> <h2><strong>4. 自定义 Authentication Provider</strong></h2> 现在让我们通过实现AuthneticationProvider接口来创建一个自定义身份验证提供程序。<br /> <br /> 我们将实施验证方法 - 它将尝试验证。 输入的Authentication对象包含用户提供的用户名和密码凭证。<br /> <br /> 如果身份验证成功,则身份验证方法会返回完全填充的身份验证对象。 如果身份验证失败,则会抛出AuthenticationException类型的异常:<br />   <pre> <code class="language-java">@Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName(); String password = auth.getCredentials() .toString(); if ("externaluser".equals(username) && "pass".equals(password)) { return new UsernamePasswordAuthenticationToken (username, password, Collections.emptyList()); } else { throw new BadCredentialsException("External system authentication failed"); } } @Override public boolean supports(Class<?> auth) { return auth.equals(UsernamePasswordAuthenticationToken.class); } }</code></pre> 当然,这是我们这里例子的一个简单实现。 <h2><strong>5. 配置Multiple Authentication Providers</strong></h2> 现在让我们将CustomAuthenticationProvider和一个内存中验证提供程序添加到我们的Spring Security配置中。 <h3><strong>5.1. Java Configuration</strong></h3> 在我们的配置类中,现在让我们使用AuthenticationManagerBuilder创建和添加身份验证提供程序。<br /> <br /> 首先,通过使用inMemoryAuthentication(),使用CustomAuthenticationProvider,然后使用内存认证提供程序。<br /> <br /> 我们还确保访问URL模式“/ api / **”需要进行身份验证: <pre> <code class="language-java">@EnableWebSecurity public class MultipleAuthProvidersSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired CustomAuthenticationProvider customAuthProvider; @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(customAuthProvider); auth.inMemoryAuthentication() .withUser("memuser") .password(encoder().encode("pass")) .roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.httpBasic() .and() .authorizeRequests() .antMatchers("/api/**") .authenticated(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }</code></pre>   <h3><strong>5.2. XML Configuration</strong></h3> 或者,如果我们想使用XML配置而不是Java配置: <pre> <code class="language-xml"><security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="memuser" password="pass" authorities="ROLE_USER" /> </security:user-service> </security:authentication-provider> <security:authentication-provider ref="customAuthenticationProvider" /> </security:authentication-manager> <security:http> <security:http-basic /> <security:intercept-url pattern="/api/**" access="isAuthenticated()" /> </security:http></code></pre> <h2><strong>6. 应用Application</strong></h2> 接下来,让我们创建一个由我们的两个身份验证提供程序保护的简单REST端点。<br /> <br /> 要访问此端点,必须提供有效的用户名和密码。 我们的身份验证提供程序将验证凭据并确定是否允许访问: <pre> <code class="language-java">@RestController public class MultipleAuthController { @GetMapping("/api/ping") public String getPing() { return "OK"; } }</code></pre>   <h2><strong>7. 测试</strong></h2> 最后,我们现在测试对安全应用程序的访问权限。 只有提供有效凭证时才允许访问: <pre> <code class="language-java">@Autowired private TestRestTemplate restTemplate; @Test public void givenMemUsers_whenGetPingWithValidUser_thenOk() { ResponseEntity<String> result = makeRestCallToGetPing("memuser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenExternalUsers_whenGetPingWithValidUser_thenOK() { ResponseEntity<String> result = makeRestCallToGetPing("externaluser", "pass"); assertThat(result.getStatusCodeValue()).isEqualTo(200); assertThat(result.getBody()).isEqualTo("OK"); } @Test public void givenAuthProviders_whenGetPingWithNoCred_then401() { ResponseEntity<String> result = makeRestCallToGetPing(); assertThat(result.getStatusCodeValue()).isEqualTo(401); } @Test public void givenAuthProviders_whenGetPingWithBadCred_then401() { ResponseEntity<String> result = makeRestCallToGetPing("user", "bad_password"); assertThat(result.getStatusCodeValue()).isEqualTo(401); } private ResponseEntity<String> makeRestCallToGetPing(String username, String password) { return restTemplate.withBasicAuth(username, password) .getForEntity("/api/ping", String.class, Collections.emptyMap()); } private ResponseEntity<String> makeRestCallToGetPing() { return restTemplate .getForEntity("/api/ping", String.class, Collections.emptyMap()); }</code></pre> <h2><strong>8. 总结</strong></h2> 在本快速教程中,我们已经看到了如何在Spring Security中配置多个身份验证提供程序。 我们使用自定义身份验证提供程序和内存身份验证提供程序确保了一个简单应用程序。<br /> <br /> 我们还编写了测试,以验证对我们应用程序的访问需要至少有一个身份验证提供程序可以验证的凭据。
  • linux安装配置svn版本管理器

    linux安装配置svn版本管理器<h2>1.安装svn</h2> <strong><em>#yum -y install svn</em></strong> <h2>2.创建SVN仓库存放路径</h2> <strong><em>$mkdir svn_java<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="mkdir svn_java" src="/assets/upload/blog/thumbnail/2017-01/cd12741d-1f78-4b93-9106-22b254705ab7.png" /></em></strong> <h2>3.创建maven仓库</h2> <strong><em>$svnadmin create /home/svn/svn_java<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="创建maven仓库" src="/assets/upload/blog/thumbnail/2017-01/8efbd7eb-539e-4120-8f7e-79138dbfcf61.png" /></em></strong> <h2>4.配置用户信息</h2> <strong><em>$cd /home/svn/svn_java/conf</em></strong><br />  <br /> <img srcset="" size="" class="img-thumbnail" alt="1" height="369" src="/assets/upload/blog/thumbnail/2017-01/8427a867-5bd7-4ed7-bc99-4fc706bf4d20.png" width="" /><br /> <strong><em>$vi passwd</em></strong><br /> <strong><em><img srcset="" size="" class="img-thumbnail" alt="2" height="249" src="/assets/upload/blog/thumbnail/2017-01/57668089-3d20-4431-bdc8-32c793d75bbc.png" width="" /></em></strong><br /> 创建一个用户名为test密码为test用户<br /> <img srcset="" size="" class="img-thumbnail" alt="3" height="229" src="/assets/upload/blog/thumbnail/2017-01/82615e94-9763-47f5-956a-c4a0c420ce8d.png" width="" /><br /> 保存并退出. <h2>5.配置仓库读写权限</h2> <strong><em>$ vi svnserve.conf</em></strong><img srcset="" size="" class="img-thumbnail" alt="1" height="797" src="/assets/upload/blog/thumbnail/2017-01/30ee6f59-241d-4c2f-8ae5-6c619a163394.png" width="" /> <h2>6. 修改authz 文件,创建svn组和组用户的权限</h2> <strong><em>$ vi authz</em></strong><br /> <strong><em><img srcset="" size="" class="img-thumbnail" alt="2" height="142" src="/assets/upload/blog/thumbnail/2017-01/450734d2-3cb9-408e-b9b3-14ee98bc6667.png" width="" /></em></strong><br /> Authz文件默认内容:<br /> <img srcset="" size="" class="img-thumbnail" alt="3" height="489" src="/assets/upload/blog/thumbnail/2017-01/7b69bb3e-1f04-4f2d-b133-111b350d8a66.png" width="" /><br /> 更改内容:<img srcset="" size="" class="img-thumbnail" alt="4" height="667" src="/assets/upload/blog/thumbnail/2017-01/51e909ec-7595-4155-94ea-a7bd2c48f9ad.png" width="" /> <h2>7.启用SVN仓库</h2> <strong><em>svnserve -d -r /home/svn/svn_java/</em></strong><br /> <strong><em><img srcset="" size="" class="img-thumbnail" alt="1" height="110" src="/assets/upload/blog/thumbnail/2017-01/d9905663-aafb-40db-83d1-6eb2b0a4ca03.png" width="" /></em></strong> <p><span style="color:#ff0000">【注意】</span><br /> <span style="color:#ff0000">1.默认端口 3690</span><br /> <span style="color:#ff0000">2.可通过启用命令修改默认端口:</span><strong><em>$svnserve --listen-port 9999 -d -r /opt/svndata</em></strong><br /> <span style="color:#ff0000">3.配置文件中,配置项前后均不能有空格,否则将会使配置错误.</span></p> <h2>===================Centos配置以service方式启动svn服务================</h2> 1.编辑配置文件/etc/sysconfig/svnserve<br /> 默认内容: <pre> <code class="language-bash">[root@localhost bin]# cat /etc/sysconfig/svnserve # OPTIONS is used to pass command-line arguments to svnserve. # # Specify the repository location in -r parameter: OPTIONS="-r /var/svn" </code></pre> 修改后: <pre> <code class="language-bash">[root@localhost bin]# cat /etc/sysconfig/svnserve # OPTIONS is used to pass command-line arguments to svnserve. # # Specify the repository location in -r parameter: #OPTIONS="-r /var/svn" OPTIONS="-d -r /home/svn/svn_java/"</code></pre> <br /> 启动svn的服务: <pre> <code class="language-bash">systemctl start svnserve.service</code></pre> 停止: <pre> <code class="language-bash">systemctl stop svnserve.service</code></pre> 重启: <pre> <code class="language-bash">systemctl restart svnserve.service</code></pre> 开机启动: <pre> <code class="language-bash">systemctl enable svnserve.service</code></pre> 取消开机启动: <pre> <code class="language-bash">systemctl disable svnserve.service</code></pre> <br /> <br /> <br />  
  • Spring框架开启自带的任务调度器执行任务(注解方式)

    Spring框架自带了一个任务调度器,虽然默认的方式只能通过配置写死,但是也可以自己适当运用1.首先需要在配置中开启spring框架自带的任务调度器,开启代码如下 <pre> <code class="language-java">import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration @EnableScheduling public class SpringScheduleConfig { } </code></pre> 2.在需要使用的地方使用注解@Scheduled来配置任务的具体调度时间等<br /> 例如: <pre> <code class="language-java">import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class TestTask { @Scheduled(cron = "00 30 02 * * ?") // 每天02:30分执行博客自动审核任务 public void deleteUnUse() { System.out.println("do somthing...."); } } </code></pre>
  • nginx window 版本配置文件nginx.conf不生效解决

    打开任务管理器发现一大堆nginx进程打开任务管理器发现一大堆nginx进程。将其结束,命令如下:taskkill /IM nginx.exe /F再次启动nginx就每问题了。总结:window 版本的nginx启动用命令 nginx.exe 或者指定文件nginx -c conf/nginx.conf。启动后如果只关闭启动时候的cmd窗口,是不会停止nginx进程的,需要手动关闭下(暂时这么解决吧。有更好的办法欢迎留言告诉我,谢谢)。
  • Gson JsonReader使用讲解

           学习使用Gson JsonReader类,这是一个基于拉的流式JSON解析器,它有助于将JSON作为标记流来读取​GSON1. JsonReader是什么JsonReader是流式JSON解析器和拉解析器的示例       学习使用Gson JsonReader类,这是一个基于拉的流式JSON解析器,它有助于将JSON作为标记流来读取​GSON1. JsonReader是什么JsonReader是流式JSON解析器和拉解析器的示例。推送解析器解析JSON令牌并将它们推送到事件处理程序中。它有助于将JSON(RFC 7159)编码值作为标记流读取。它读取文字值(字符串,数字,布尔值和空值)以及对象和数组的开始和结束分隔符。标记以深度优先顺序遍历,与它们在JSON文档中出现的顺序相同。2. Tokens在流模式下,每个JSON数据都被视为单个令牌。当我们用JsonReader它来处理它时,每个令牌将按顺序处理。例如,$title(Json Tokens) { "name":"Lokesh" } 在使用JsonReader进行解析时,上面的JSON将生成4个token:Token 1 = {Token 2 = nameToken 3 = LokeshToken 4 = }3.如何创建GSON JsonReader 我们可以JsonReader使用它接受java.io.Reader类型输入流的简单构造函数创建一个实例。$title(Create JsonReader) String json = "{}"; JsonReader jsonReader = new JsonReader( new StringReader(json) ); 我们可以根据JSON流的来源使用以下读者之一:BufferedReaderLineNumberReaderCharArrayReaderInputStreamReaderFileReaderFilterReaderPushbackReaderPipedReaderStringReader4.读取JSON Stream 在创建JsonReader包装有效的JSON源之后,我们可以开始迭代流令牌并查看令牌值。以下是在令牌上使用表单中的JsonReader读取简单JSON的示例。$title(JsonReader Example) import java.io.IOException; import java.io.StringReader; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; public class Main { public static void main(String[] args) throws Exception { String json = "{'id': 1001,'firstName': 'Lokesh','lastName': 'Gupta','email': null}"; JsonReader jsonReader = new JsonReader(new StringReader(json)); jsonReader.setLenient(true); try { while (jsonReader.hasNext()) { JsonToken nextToken = jsonReader.peek(); if (JsonToken.BEGIN_OBJECT.equals(nextToken)) { jsonReader.beginObject(); } else if (JsonToken.NAME.equals(nextToken)) { String name = jsonReader.nextName(); System.out.println("Token KEY >>>> " + name); } else if (JsonToken.STRING.equals(nextToken)) { String value = jsonReader.nextString(); System.out.println("Token Value >>>> " + value); } else if (JsonToken.NUMBER.equals(nextToken)) { long value = jsonReader.nextLong(); System.out.println("Token Value >>>> " + value); } else if (JsonToken.NULL.equals(nextToken)) { jsonReader.nextNull(); System.out.println("Token Value >>>> null"); } else if (JsonToken.END_OBJECT.equals(nextToken)) { jsonReader.endObject(); } } } catch (IOException e) { e.printStackTrace(); } finally { jsonReader.close(); } } } 执行输出:Token KEY >>>> id Token Value >>>> 1001 Token KEY >>>> firstName Token Value >>>> Lokesh Token KEY >>>> lastName Token Value >>>> Gupta Token KEY >>>> email Token Value >>>> null 在上面的例子中:令牌的键是JsonToken.NAME类型。使用nextName()方法获取密钥名称。如果hasNext()方法JsonReader有更多的标记,则返回true 的hasNext()方法。的PEEK()方法返回下一个令牌JSON,但不移动在它。对peek()随后的多次调用将返回相同的JSON令牌。可以使用JsonToken类的常量检查返回标记的类型。Array的开启和关闭括号'[',并']'与检查beginArray()和endArray()方法。Object的开始和结束括号'{','}'并使用beginObject()和endObject()方法进行检查。确定令牌的类型后,获得令牌的使用方法的类似的值nextLong(),nextString(),nextInt()等。空文字可以使用任何消耗nextNull()或skipValue()。所有next....()方法都返回当前标记的值,并将内部指针移动到下一个标记。遇到未知名称时,严格的解析器应该失败并出现异常。宽松解析器应该调用skipValue()以递归方式跳过值的嵌套标记,否则可能会发生冲突。
  • Java编程设计模式之构建模式

    以前我们看过工厂和抽象工厂模式。这些模式可以达到其目的,并且可以非常有用,但是有一些用例我们必须创建一个非常复杂的对象,并且创建它需要不同的步骤,每个步骤都需要不同的操作。在这种情况下,构建器模式可能非常有用。<h2>引言</h2> <blockquote> <p>以前我们看过工厂和抽象工厂模式。这些模式可以达到其目的,并且可以非常有用,但是有一些用例我们必须创建一个非常复杂的对象,并且创建它需要不同的步骤,每个步骤都需要不同的操作。在这种情况下,构建器模式可能非常有用。</p> </blockquote> <h2>什么是构建模式</h2> 构建器设计模式是一种创建式设计模式,可用于逐步创建复杂对象。<br /> <br /> 假设我们有一个具有很多依赖关系的对象,并且为了获得这些依赖关系中的每一个,必须发布一些特定的动作。<br /> 在这种情况下,我们可以使用构建器模式 <ul style="margin-left:10px; margin-right:0px"> <li>封装在一个单独的<code>Builder</code> 对象中创建和组装一个复杂对象的各个部分  。</li> <li>将对象创建委托给  <code>Builder</code> 对象而不是直接创建对象。</li> </ul> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">想象一下后端系统需要编写和发送邮件的场景。<br /> 创建电子邮件可能是一个复杂的过程。您必须指定标题,设置收件人,添加问候语添加结束语句。您可能也想使用<a href="http://mustache.github.io/" rel="external nofollow" style="padding:0px; margin:0px; outline:none; list-style:none; border:0px none; color:#326693; text-decoration:none; transition:all 0.2s ease-in-out" target="_blank">小胡子</a>。有多种选择。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">有一个类需要创建一个电子邮件的所有行动可能会使我们的课程臃肿和松散的原始目的。</span></span></span></p> <p style="text-align:start"><span style="color:#333333"><span style="font-family:Tahoma,Arial,Verdana,sans-serif"><span style="background-color:#ffffff">所以我们将从负责发送电子邮件的班级开始。</span></span></span></p> <pre> <code class="language-java">public class Email { private final String title; private final String recipients; private final String message; public Email(String title, String recipients, String message) { this.title = title; this.recipients = recipients; this.message = message; } public String getTitle() { return title; } public String getRecipients() { return recipients; } public String getMessage() { return message; } public void send() { } }</code></pre> <br /> 正如你所看到的,这个类只包含三个字符串字段,并且没有额外的处理。因此,我们将创建一个构建器类,它将处理邮件格式,收件人表示和创建电子邮件类。 <pre> <code class="language-java">public class EmailBuilder { private Set recipients = new HashSet(); private String title; private String greeting; private String mainText; private String closing; public EmailBuilder addRecipient(String recipient) { this.recipients.add(recipient); return this; } public EmailBuilder removeRecipient(String recipient) { this.recipients.remove(recipient); return this; } public EmailBuilder setTitle(String title) { this.title = title; return this; } public EmailBuilder setGreeting(String greeting) { this.greeting = greeting; return this; } public EmailBuilder setMainText(String mainText) { this.mainText = mainText; return this; } public EmailBuilder setClosing(String closing) { this.closing = closing; return this; } public Email create() { String message = greeting+"\n"+mainText+"\n"+closing; String recipientSection = commaSeparatedRecipients(); return new Email(title,recipientSection,message); } private String commaSeparatedRecipients() { StringBuilder sb = new StringBuilder(); for(String recipient:recipients) { sb.append(",").append(recipient); } return sb.toString().replaceFirst(",",""); } }</code></pre> <br /> 接下来是使电子邮件创建更加严格的步骤,以便只有通过EmailBuilder才能创建电子邮件。 <pre> <code class="language-java">public class Email { private final String title; private final String recipients; private final String message; private Email(String title, String recipients, String message) { this.title = title; this.recipients = recipients; this.message = message; } public String getTitle() { return title; } public String getRecipients() { return recipients; } public String getMessage() { return message; } public void send() { } public static class EmailBuilder { private Set recipients = new HashSet(); private String title; private String greeting; private String mainText; private String closing; public EmailBuilder addRecipient(String recipient) { this.recipients.add(recipient); return this; } public EmailBuilder removeRecipient(String recipient) { this.recipients.remove(recipient); return this; } public EmailBuilder setTitle(String title) { this.title = title; return this; } public EmailBuilder setGreeting(String greeting) { this.greeting = greeting; return this; } public EmailBuilder setMainText(String mainText) { this.mainText = mainText; return this; } public EmailBuilder setClosing(String closing) { this.closing = closing; return this; } public Email build() { String message = greeting+"\n"+mainText+"\n"+closing; String recipientSection = commaSeparatedRecipients(); return new Email(title,recipientSection,message); } private String commaSeparatedRecipients() { StringBuilder sb = new StringBuilder(); for(String recipient:recipients) { sb.append(",").append(recipient); } return sb.toString().replaceFirst(",",""); } } }</code></pre> <br /> 使用构建器模式创建电子邮件的最终结果就是这样。 <pre> <code class="language-java">Email email = new Email.EmailBuilder() .addRecipient("john@Doe.com") .setMainText("Check the builder pattern") .setGreeting("Hi John!") .setClosing("Regards") .setTitle("Builder pattern resources") .build();</code></pre> 通过使用构建器模式进行总结,我们能够创建一个复杂的对象及其复杂的部分。
  • Spring Boot Mybatis Shiro 中出现事务不生效原因及解决办法

    出现@Transactional事务不生效原因shiro 的Realm 中注入了用到事务的service,例如下面的​ /** * 自定义权限认证器 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权出现@Transactional事务不生效原因shiro 的Realm 中注入了用到事务的service,例如下面的​ /** * 自定义权限认证器 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权 */ public class UserRealm extends AuthorizingRealm {    //超管账号    @Value("${super.user}")    String su;            @Autowired    SystemUserService systemUserService; ​      @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {       // TODO CODE ...        return info;   } ​    /***     * 登录鉴定(就是鉴定用户是否登录)     * @param authenticationToken     * @return     * @throws AuthenticationException     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {       // TODO CODE ...        return info;   } } ​按上方代码使用,SystemUserService 这个service中所有的事务都将不会生效。原因细节首先我们在项目整合Shiro的时候通过ShiroConfig做了一些配置,其中一项包括Shiro的授权认证器MemberAuthorizingRealm。在UserRealm中我们通过@Autowired注入了本篇的主角SystemUserService。Spring启动的时候,配置相关的都是优先初始化的,在初始化UserRealm的时候发现需要注入一个SystemUserService对象,容器里肯定是没有的,那么就提前将其初始化了。此时如果在MemberService还有通过@Autowired注入的其他依赖,那么会一并初始化,依赖中要是还有依赖会继续递归初始化,这样下来会导致一系列的实例都是没有被代理的。但是这时候Spring中创建代理的处理器是还没有的,导致SystemUserService的BeanPostProcessor中没有AbstractAutoProxyCreator这个对象,后面整个BeanPostProcessor列表执行的时候没有为其创建代理。Spring中的数据库事务都是需要代理支持的,所以MemberService中不能开启事务。解决办法方法一(推荐):在Realm中注入的service上面添加@Lazy注解/** * 自定义权限认证器 * 自定义实现Realm,实现自定义获取登录信息进行登录鉴权和获取权限信息进行权限鉴权 */ public class UserRealm extends AuthorizingRealm {    //超管账号    @Value("${super.user}")    String su;        @Lazy    @Autowired    SystemUserService systemUserService; ​      @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {       // TODO CODE ...        return info;   } ​    /***     * 登录鉴定(就是鉴定用户是否登录)     * @param authenticationToken     * @return     * @throws AuthenticationException     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {       // TODO CODE ...        return info;   } }方法二:单独创建一个service直接和mapper打交道,然后注入到Realm中方法三:通过spring application getBean获取 service