搜索词>>SpringBoot 耗时0.0040
  • springboot 使用thymeleaf url get请求传多个参数问题解决

    springboot 使用thymeleaf 模板引擎中url中的&引起的org.xml.sax.SAXParseException: 对实体 "uid" 的引用必须以 ';' 分隔符结尾。问题解决<h2>1.问题描述</h2> 在使用thymeleaf模板中,有些时候需要绝对路径带多个参数的地址访问其他页面,这时候由于&字符的问题会报错:<br /> org.xml.sax.SAXParseException: 对实体 "xxx" 的引用必须以 ';' 分隔符结尾。 <h2>2.问题解决</h2> 使用逆转字符代替&,>,<这些符号<br /> 例如: <pre> <code class="language-html"><a class="third-login-qq" href="https://graph.qq.com/oauth2.0/authorize? response_type=code&amp;client_id=101395666&amp;redirect_uri=http://www.leftso.com/user/login.html&amp;scope=get_user_info&amp;state=test" id="qqLoginBtn"></a></code></pre>
  • spring boot filter 配置使用

    在Java编程中,web项目通常会使用一些filter处理一些特定的业务。这里主要讲解springboot中filter的几种配置和使用。<h2>引言</h2>     在Java编程中,web项目通常会使用一些filter处理一些特定的业务。这里主要讲解springboot中filter的几种配置和使用。 <h2>一.创建一个spring boot 项目</h2> 创建spring boot项目的方法这里就不详细介绍了,不清楚的可以参考:<a rel="" href="http://www.leftso.com/blog/64.html" rel="" target="_blank">spring boot 入门项目创建</a><br /> 下面是一个创建好的项目结构图:<br /> <img alt="项目结构图" class="img-thumbnail" src="/resources/assist/images/blog/33b5edbb638b4554b07ee0e9de2c5bbe.png" /><br /> 其中主要的在于上面的config目录下的FilterConfig.java和下面的filter中两个filter的实现类。 <h2>二.Filter的实现类</h2> 这里的filter指的是javax.servlet.Filter;接口。在spring boot框架中有很多方式来实现Filter接口。下面就讲常用的两种。 <h3>2.1javax.servlet.Filter;原生接口的实现</h3> <strong>MyFilter.java:</strong> <pre> <code class="language-java">package net.xqlee.project.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 测试用filter * * @author xqlee * */ public class MyFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(MyFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("MyFilter 初始化中..."); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { log.info("进入 MyFilter"); chain.doFilter(request, response); } @Override public void destroy() { log.info("MyFilter 销毁中..."); } } </code></pre> 上面的代码就是一个简单的Filter接口实现类.其中需要处理的业务一般放在doFilter方法中。 <h3>2.2继承spring的OncePerRequestFilter来实现Filter</h3> <pre> <code class="language-java">package net.xqlee.project.filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.filter.OncePerRequestFilter; /** * 通过继承spring提供的filter来实现filter * * @author xqlee * */ public class MyOncePerRequestFilter extends OncePerRequestFilter { private static final Logger log = LoggerFactory.getLogger(MyOncePerRequestFilter.class); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { log.info("进入 MyOncePerRequestFilter"); filterChain.doFilter(request, response); } } </code></pre> 说明:Spring 的OncePerRequestFilter类实际上是一个实现了Filter接口的抽象类。spring对Filter进行了一些封装处理。 <h2>三.配置Filter到容器中</h2>     上面只是创建好了两个Filter实现类。在web编程中我们知道需要在web.xml中配置相应的过滤器内容,如过滤的url,过滤器名字,参数等。spring boot框架中为配置Filter进行了一些封装使得我们可以用spring风格的方式配置Filter。<br /> 首先创建一个类,添加配置注解,并将上面的两个过滤器配置到这个配置类中: <pre> <code class="language-java">package net.xqlee.project.config; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import net.xqlee.project.filter.MyFilter; import net.xqlee.project.filter.MyOncePerRequestFilter; /** * 配置拦截器 * * @author xqlee * */ @Configuration public class FilterConfig { /** * 拦截器注册 * * @return */ @Bean public FilterRegistrationBean myFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MyFilter()); registration.addUrlPatterns("/a/*");// 拦截路径 registration.setName("MyFilter");// 拦截器名称 registration.setOrder(1);// 顺序 return registration; } /** * 拦截器注册 * * @return */ @Bean public FilterRegistrationBean myOncePerRequestFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MyOncePerRequestFilter()); registration.addUrlPatterns("/*");// 拦截路径 registration.setName("MyOncePerRequestFilter");// 拦截器名称 registration.setOrder(2);// 顺序 return registration; } } </code></pre> <h2>四.Spring boot Filter测试</h2> 启动spring boot项目,观察启动日志:<br /> <img alt="" class="img-thumbnail" src="/resources/assist/images/blog/d5157c396bc8402e87c5567c843a6701.png" />注意观察上图中红色圈出来的地方,我们可以看到两个filter都进行了初始化并且也显示出来了过滤器的过滤地址。<br /> <br /> 为了进一步的测试其是否作用,创建一个简单的controller进行测试 <pre> <code class="language-java">package net.xqlee.project.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("/a/filter.do") public Object hello() { return "Hello Filter"; } @GetMapping("/") public Object index() { return "Welcome Index"; } } </code></pre> <br /> 浏览器访问地址http://localhost:8080/<br /> <img alt="index" class="img-thumbnail" src="/resources/assist/images/blog/73d5d31bbfa040d6a97be4945d93a49b.png" /><br /> 观察eclipse控制台日志:<br /> <img alt="访问日志" class="img-thumbnail" src="/resources/assist/images/blog/bae81d12286e4a5a8caa859cb14ac40a.png" /><br /> 我们可以看到只有MyOncePerRequestFilter的日志,因为从启动日志图中可以看到MyOncePerRequestFilter的过滤路径是所有,而myfilter过滤路径是/a/,所以这里只能看到MyOncePerRequestFilter的日志。<br /> <br /> 接下来访问地址:http://localhost:8080/a/filter.do<br /> <img alt="访问" class="img-thumbnail" src="/resources/assist/images/blog/0dfedd8e8c8b43e9bc54a99247c1c102.png" /><br /> 后端日志:<br /> <img alt="" class="img-thumbnail" src="/resources/assist/images/blog/3dd625c90b0d454eba69436e04ae5c52.png" />这次可以看到两个过滤器的日志了。同时也说明配置的过滤器已经生效。<br /> <br />  
  • spring boot RabbitMQ基本集成使用

    spring boot RabbitMQ基本集成使用spring boot RabbitMQ基本集成使用 <h2>RabbitMQ介绍</h2> <p>RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。RabbitMQ主要是为了实现系统之间的双向解耦而实现的。当生产者大量产生数据时,消费者无法快速消费,那么需要一个中间层。保存这个数据。</p> <p>AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。</p> <p>RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。</p> <h2>相关概念</h2> 通常我们谈到队列服务, 会有三个概念: 发消息者、队列、收消息者,RabbitMQ 在这个基本概念之上, 多做了一层抽象, 在发消息者和 队列之间, 加入了交换器 (Exchange). 这样发消息者和队列就没有直接联系, 转而变成发消息者把消息给交换器, 交换器根据调度策略再把消息再给队列。<br /> <img alt="" class="img-thumbnail" src="/resources/assist/images/blog/c3db0eeb8a2d40d3a9a1437c424b9934.jpg" /> <p>左侧 P 代表 生产者,也就是往 RabbitMQ 发消息的程序。</p> <ul> <li> <p>中间即是 RabbitMQ,<em>其中包括了 交换机 和 队列。</em></p> </li> <li> <p>右侧 C 代表 消费者,也就是往 RabbitMQ 拿消息的程序。</p> </li> </ul> <p>那么,<em>其中比较重要的概念有 4 个,分别为:虚拟主机,交换机,队列,和绑定。</em></p> <ul> <li> <p>虚拟主机:一个虚拟主机持有一组交换机、队列和绑定。为什么需要多个虚拟主机呢?很简单,RabbitMQ当中,<em>用户只能在虚拟主机的粒度进行权限控制。</em> 因此,如果需要禁止A组访问B组的交换机/队列/绑定,必须为A和B分别创建一个虚拟主机。每一个RabbitMQ服务器都有一个默认的虚拟主机“/”。</p> </li> <li> <p>交换机:<em>Exchange 用于转发消息,但是它不会做存储</em> ,如果没有 Queue bind 到 Exchange 的话,它会直接丢弃掉 Producer 发送过来的消息。<br /> 这里有一个比较重要的概念:<strong>路由键</strong> 。消息到交换机的时候,交互机会转发到对应的队列中,那么究竟转发到哪个队列,就要根据该路由键。</p> </li> <li> <p>绑定:也就是交换机需要和队列相绑定,这其中如上图所示,是多对多的关系。</p> </li> </ul> <h3>交换机(Exchange)</h3> <p>交换机的功能主要是接收消息并且转发到绑定的队列,交换机不存储消息,在启用ack模式后,交换机找不到队列会返回错误。交换机有四种类型:Direct, topic, Headers and Fanout</p> <ul> <li> <p>Direct:direct 类型的行为是”先匹配, 再投送”. 即在绑定时设定一个 <strong>routing_key</strong>, 消息的<strong>routing_key</strong> 匹配时, 才会被交换器投送到绑定的队列中去.</p> </li> <li> <p>Topic:按规则转发消息(最灵活)</p> </li> <li> <p>Headers:设置header attribute参数类型的交换机</p> </li> <li> <p>Fanout:转发消息到所有绑定队列</p> </li> </ul> <p><strong>Direct Exchange</strong><br /> Direct  Exchange是RabbitMQ默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。<br /> <img alt="生产消费关系图" class="img-thumbnail" src="/resources/assist/images/blog/a50800a7e550419ebed551dd4f2cd5aa.png" /><br />  </p> <p>第一个 X - Q1 就有一个 binding key,名字为 orange; X - Q2 就有 2 个 binding key,名字为 black 和 green。<em>当消息中的 路由键 和 这个 binding key 对应上的时候,那么就知道了该消息去到哪一个队列中。</em></p> <p>Ps:为什么 X 到 Q2 要有 black,green,2个 binding key呢,一个不就行了吗? - 这个主要是因为可能又有 Q3,而Q3只接受 black 的信息,而Q2不仅接受black 的信息,还接受 green 的信息。</p> <p><strong>Topic Exchange</strong>  </p> <p><em>Topic Exchange 转发消息主要是根据通配符。</em> 在这种交换机下,队列和交换机的绑定会定义一种路由模式,那么,通配符就要在这种路由模式和路由键之间匹配后交换机才能转发消息。</p> <p>在这种交换机模式下:</p> <ul> <li> <p>路由键必须是一串字符,用句号(<code>.</code>) 隔开,比如说 agreements.us,或者 agreements.eu.stockholm 等。</p> </li> <li> <p>路由模式必须包含一个 星号(<code>*</code>),主要用于匹配路由键指定位置的一个单词,比如说,一个路由模式是这样子:agreements..b.*,那么就只能匹配路由键是这样子的:第一个单词是 agreements,第四个单词是 b。 井号(#)就表示相当于一个或者多个单词,例如一个匹配模式是agreements.eu.berlin.#,那么,以agreements.eu.berlin开头的路由键都是可以的。</p> </li> </ul> <p>具体代码发送的时候还是一样,第一个参数表示交换机,第二个参数表示routing key,第三个参数即消息。如下:<br />  </p> <pre> <code class="language-html">rabbitTemplate.convertAndSend("testTopicExchange","key1.a.c.key2", " this is RabbitMQ!");</code></pre> <p>topic 和 direct 类似, 只是匹配上支持了”模式”, 在”点分”的 routing_key 形式中, 可以使用两个通配符:</p> <ul> <li> <p><code>*</code>表示一个词.</p> </li> <li> <p><code>#</code>表示零个或多个词.</p> </li> </ul> <p><strong>Headers Exchange</strong></p> <p>headers 也是根据规则匹配, 相较于 direct 和 topic 固定地使用 routing_key , headers 则是一个自定义匹配规则的类型.<br /> 在队列与交换器绑定时, 会设定一组键值对规则, 消息中也包括一组键值对( headers 属性), 当这些键值对有一对, 或全部匹配时, 消息被投送到对应队列.</p> <p><strong>Fanout Exchange</strong></p> <p>Fanout Exchange 消息广播的模式,不管路由键或者是路由模式,<em>会把消息发给绑定给它的全部队列</em>,如果配置了routing_key会被忽略。</p> <h2>springboot集成RabbitMQ</h2> springboot集成RabbitMQ非常简单,如果只是简单的使用配置非常少,springboot提供了spring-boot-starter-amqp项目对消息各种支持。 <h3>简单使用</h3> 1、配置pom包,主要是添加spring-boot-starter-amqp的支持 <pre> <code class="language-xml"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>x</code></pre> <p>2、配置文件</p> <p>配置rabbitmq的安装地址、端口以及账户信息<br />  </p> <pre> <code class="language-html">spring.application.name=spirng-boot-rabbitmq spring.rabbitmq.host=192.168.0.86 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=123456</code></pre> 3、队列配置 <pre> <code class="language-java">@Configuration public class RabbitConfig { @Bean public Queue Queue() { return new Queue("hello"); } }</code></pre> <p>4、发送者</p> <p>rabbitTemplate是springboot 提供的默认实现<br />  </p> <pre> <code class="language-java">public class HelloSender { @Autowired private AmqpTemplate rabbitTemplate; public void send() { String context = "hello " + new Date(); System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("hello", context); } }</code></pre> 5、接收者 <pre> <code class="language-java">@Component @RabbitListener(queues = "hello") public class HelloReceiver { @RabbitHandler public void process(String hello) { System.out.println("Receiver : " + hello); } }</code></pre> 6、测试 <pre> <code class="language-java">@RunWith(SpringRunner.class) @SpringBootTest public class RabbitMqHelloTest { @Autowired private HelloSender helloSender; @Test public void hello() throws Exception { helloSender.send(); } }</code></pre> <blockquote> <p>注意,发送者和接收者的queue name必须一致,不然不能接收</p> </blockquote> <h3>多对多使用</h3> <p>一个发送者,N个接收者或者N个发送者和N个接收者会出现什么情况呢?</p> <p><strong>一对多发送</strong><br /> 对上面的代码进行了小改造,接收端注册了两个Receiver,Receiver1和Receiver2,发送端加入参数计数,接收端打印接收到的参数,下面是测试代码,发送一百条消息,来观察两个接收端的执行效果<br />  </p> <pre> <code class="language-java">@Test public void oneToMany() throws Exception { for (int i=0;i<100;i++){ neoSender.send(i); } }</code></pre> 结果如下: <pre> <code class="language-html">Receiver 1: spirng boot neo queue ****** 11 Receiver 2: spirng boot neo queue ****** 12 Receiver 2: spirng boot neo queue ****** 14 Receiver 1: spirng boot neo queue ****** 13 Receiver 2: spirng boot neo queue ****** 15 Receiver 1: spirng boot neo queue ****** 16 Receiver 1: spirng boot neo queue ****** 18 Receiver 2: spirng boot neo queue ****** 17 Receiver 2: spirng boot neo queue ****** 19 Receiver 1: spirng boot neo queue ****** 20</code></pre> <br /> 根据返回结果得到以下结论 <blockquote> <p>一个发送者,N个接受者,经过测试会均匀的将消息发送到N个接收者中</p> </blockquote> <p><strong>多对多发送</strong>  </p> <p>复制了一份发送者,加入标记,在一百个循环中相互交替发送<br />  </p> <pre> <code class="language-java">@Test public void manyToMany() throws Exception { for (int i=0;i<100;i++){ neoSender.send(i); neoSender2.send(i); } }</code></pre> 结果如下: <pre> <code class="language-html">Receiver 1: spirng boot neo queue ****** 20 Receiver 2: spirng boot neo queue ****** 20 Receiver 1: spirng boot neo queue ****** 21 Receiver 2: spirng boot neo queue ****** 21 Receiver 1: spirng boot neo queue ****** 22 Receiver 2: spirng boot neo queue ****** 22 Receiver 1: spirng boot neo queue ****** 23 Receiver 2: spirng boot neo queue ****** 23 Receiver 1: spirng boot neo queue ****** 24 Receiver 2: spirng boot neo queue ****** 24 Receiver 1: spirng boot neo queue ****** 25 Receiver 2: spirng boot neo queue ****** 25</code></pre> <blockquote> <p>结论:和一对多一样,接收端仍然会均匀接收到消息</p> </blockquote> <h3>高级使用</h3> <p><strong>对象的支持</strong></p> <p>springboot以及完美的支持对象的发送和接收,不需要格外的配置。<br />  </p> <pre> <code class="language-java">//发送者 public void send(User user) { System.out.println("Sender object: " + user.toString()); this.rabbitTemplate.convertAndSend("object", user); } ... //接收者 @RabbitHandler public void process(User user) { System.out.println("Receiver object : " + user); }</code></pre> 结果如下: <pre> <code class="language-html">Sender object: User{name='neo', pass='123456'} Receiver object : User{name='neo', pass='123456'}</code></pre> <p><strong>Topic Exchange</strong></p> <p>topic 是RabbitMQ中最灵活的一种方式,可以根据routing_key自由的绑定不同的队列</p> <p>首先对topic规则配置,这里使用两个队列来测试<br />  </p> <pre> <code class="language-java">@Configuration public class TopicRabbitConfig { final static String message = "topic.message"; final static String messages = "topic.messages"; @Bean public Queue queueMessage() { return new Queue(TopicRabbitConfig.message); } @Bean public Queue queueMessages() { return new Queue(TopicRabbitConfig.messages); } @Bean TopicExchange exchange() { return new TopicExchange("exchange"); } @Bean Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) { return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message"); } @Bean Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) { return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#"); } }</code></pre> 使用queueMessages同时匹配两个队列,queueMessage只匹配”topic.message”队列 <pre> <code class="language-java">public void send1() { String context = "hi, i am message 1"; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("exchange", "topic.message", context); } public void send2() { String context = "hi, i am messages 2"; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("exchange", "topic.messages", context); }</code></pre> <p>发送send1会匹配到topic.#和topic.message 两个Receiver都可以收到消息,发送send2只有topic.#可以匹配所有只有Receiver2监听到消息</p> <p><strong>Fanout Exchange</strong></p> <p>Fanout 就是我们熟悉的广播模式或者订阅模式,给Fanout交换机发送消息,绑定了这个交换机的所有队列都收到这个消息。</p> <p>Fanout 相关配置<br />  </p> <pre> <code class="language-java">@Configuration public class FanoutRabbitConfig { @Bean public Queue AMessage() { return new Queue("fanout.A"); } @Bean public Queue BMessage() { return new Queue("fanout.B"); } @Bean public Queue CMessage() { return new Queue("fanout.C"); } @Bean FanoutExchange fanoutExchange() { return new FanoutExchange("fanoutExchange"); } @Bean Binding bindingExchangeA(Queue AMessage,FanoutExchange fanoutExchange) { return BindingBuilder.bind(AMessage).to(fanoutExchange); } @Bean Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) { return BindingBuilder.bind(BMessage).to(fanoutExchange); } @Bean Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) { return BindingBuilder.bind(CMessage).to(fanoutExchange); } }</code></pre> 这里使用了A、B、C三个队列绑定到Fanout交换机上面,发送端的routing_key写任何字符都会被忽略: <pre> <code class="language-java">public void send() { String context = "hi, fanout msg "; System.out.println("Sender : " + context); this.rabbitTemplate.convertAndSend("fanoutExchange","", context); }</code></pre> 结果如下: <pre> <code class="language-html">Sender : hi, fanout msg ... fanout Receiver B: hi, fanout msg fanout Receiver A : hi, fanout msg fanout Receiver C: hi, fanout msg</code></pre> <blockquote> <p>结果说明,绑定到fanout交换机上面的队列都收到了消息</p> </blockquote>
  • Spring Boot validation整合hibernate validator实现数据验证

    Spring Boot validation整合hibernate validator实现数据验证,Spring Boot validation使用说明,Spring Boot validation使用教程<h2>引言</h2>     这里主要讲解在Spring  Boot项目中整合hibernate validator框架实现Spring  Boot项目的validation 验证机制。方便后端验证前端或者接口传递过来的数据格式是否正确。 <h2>一.准备环境</h2> <ul> <li>jdk1.8+(Spring Boot项目推荐使用1.8)</li> <li>eclipse(或者你喜欢的IDE)</li> <li>maven 3+</li> </ul> <h2>二.编码实现Spring Boot validation</h2> <h3>2.1创建一个spring boot项目并添web模块和validation模块</h3> 项目结构图如下:<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="spring boot项目结果图" src="/resources/assist/images/blog/017be0b2e4e848cb9bc98279929d073a.png" /><br /> 项目的依赖文件: <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project.demo</groupId> <artifactId>demo-springboot-hibernate-validator</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-springboot-hibernate-validator</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter- </artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> <h3> </h3> <blockquote> <h3>注意:</h3> <pre> <code class="language-xml"> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency></code></pre> 该模块会自动加载hibernate-validation依赖。不要自己手动配置谨防依赖问题</blockquote> <h3><br /> 2.2编写一个测试的简单对象POJO</h3> <pre> <code class="language-java">package net.xqlee.project.demo.pojo; import javax.validation.constraints.Pattern; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotBlank; import org.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.Range; public class User { @NotBlank(message = "用户名称不能为空。") private String name; @Range(max = 150, min = 1, message = "年龄范围应该在1-150内。") private Integer age; @NotEmpty(message = "密码不能为空") @Length(min = 6, max = 8, message = "密码长度为6-8位。") @Pattern(regexp = "[a-zA-Z]*", message = "密码不合法") private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } </code></pre> 细心的朋友可能已经发现一些属性上的注解。验证框架正是实现了这些注解的具体验证。hibernate在java的JSR-303标准上还添加了一些额外的验证注解实现。这些实现都为我们后端验证数据取得了巨大的方便。 <blockquote> <p>提示:<br /> 验证注解推荐使用</p> <p>javax.validation.constraints包下的注解,不要使用hibernate的<br /> 在2.0中hibernate的很多注解已经弃用,但是</p> <p>javax.validation.constraints包下的注解增多增强<br /> 一种规范性的趋势</p> </blockquote> <h3>2.3编写一个controller用于测试验证机制</h3> <pre> <code class="language-java">package net.xqlee.project.demo.controller; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import net.xqlee.project.demo.pojo.User; @RestController public class ValidatorController { private static final Logger log = LoggerFactory.getLogger(ValidatorController.class); /** * 验证框架使用测试 * * @param user * @param result */ @PostMapping("v/t1.json") public void v1(@Validated User user, BindingResult result) { StringBuilder sBuilder = new StringBuilder(); sBuilder.append("\n"); if (result.hasErrors()) { List<ObjectError> list = result.getAllErrors(); for (ObjectError error : list) { log.info(error.getCode() + "---" + error.getArguments() + "---" + error.getDefaultMessage()); sBuilder.append(error.getDefaultMessage()); sBuilder.append("\n"); } } log.info(sBuilder.toString()); } } </code></pre> <blockquote> <p>提示:<br /> @Validated (org.springframework.validation.annotation)<br /> 或者@Valid(javax.validation)<br /> 验证注解推荐写在方法的参数列表中,例如:<br /> Object   methodName(@Valid Object params){...}<br /> Object   methodName(@Validated Object params){...}<br /> <br />  </p> </blockquote> <h2><br /> 三.演示</h2> <h3>3.1启动spring boot项目</h3> <h3>3.2通过工具postmain进行提交数据验证</h3> <strong>第一组测试:</strong><br /> <br /> 提交全部为空数据:<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="spring boot validation测试数据1" src="/resources/assist/images/blog/8d1b26436c0f42b382e4aa7378e4c466.png" /><br /> 观察eclipse的控制台输出:<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="Spring Boot validation 控制台输出1" src="/resources/assist/images/blog/6b5e924b8c57446ab125be2043cec0e3.png" /><br /> 可以看到非空验证已经实现。<br /> <br /> <strong>第二组测试:</strong><br /> <br /> 接下来输入一个非空的名称和密码<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="spring boot validation测试数据2" src="/resources/assist/images/blog/d86badcd7bc44cdba5080e8f87406023.png" /><br /> 观察eclipse控制台:<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="Spring Boot validation 控制台输出2" src="/resources/assist/images/blog/87f994b3a6eb4bf9a77f3ce652471c11.png" /><br /> 可以看到名称的验证错误信息已经没有说明已经输入正确。但是密码却没有通过正则表达式的验证所以报错不合法,在对象上我们设置的密码只能是大写的字母。所以刚才输入的全数字不合法。<br /> <br /> <strong>第三组测试:</strong><br /> <br /> 接下来输入正常的密码<br /> <img srcset="" width="" size="" class="img-thumbnail" alt="spring boot validation测试数据3" src="/resources/assist/images/blog/40be7f44b6144ade956b3453ae420766.png" />观察控制台:<br /> <br /> <img srcset="" width="" size="" class="img-thumbnail" alt="Spring Boot validation 控制台输出3" src="/resources/assist/images/blog/2be73b7acb544f22845efacbb9c58a6f.png" /><br /> 可以看到已经没有错误信息。验证通过
  • spring boot 1.5.2整合mybaties日志打印出sql语句

    本文主要讲解spring boot框架整合mybaties后,如何打印出mybaties的sql语句以及参数列表本文主要讲解spring boot框架整合mybaties后,如何打印出mybaties的sql语句以及参数列表<br /> 其实办法很简单<br /> 在springboot项目中有一个application.properties属性配置文件,在该配置文件中加入以下代码即可 <pre> <code>logging.level.com.leftso.mapper=DEBUG</code></pre> <br /> <span style="color:#1abc9c">解释:<br /> 其中只需要将com.leftso.mapper改为你自己的mapper接口存放的包路径就OK</span>
  • spring boot RPC 框架 Hessian

    spring boot RPC 框架 Hessian,本文主要讲解spring boot整合hessian实现Spring boot RPC调用和Spring boot rpc框架hessian的使用。在微服务中经常遇到一个服务需要调用另外的服务这种内部调用的方式有RPC的方式。<h2>一.背景说明</h2>  该博客主要讲述的是spring boot整合hession实现Java编程中的RPC(远程调用)。实现RPC的方式还有很多例如Java的RMI,webservice等。这里主要讲解hessian的方式。 <h2>二.hessian服务端</h2> <h3>2.1创建一个spring boot项目添加web依赖和hessian依赖</h3> pom.xml如下: <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project</groupId> <artifactId>demo-springboot-rpc-hessian-server</artifactId> <version>2.0</version> <packaging>jar</packaging> <name>demo-springboot-rpc-hessian-server</name> <description>lee-leftso-v2.0</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.caucho/hessian --> <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.51</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> <h3>2.2创建一个简单的service接口并实现</h3> HelloWorldServcie.java接口: <pre> <code class="language-java">package net.xqlee.project.service; public interface HelloWorldService { String sayHello(String name); } </code></pre> HelloWorldServiceServiceImp.java <pre> <code class="language-java">package net.xqlee.project.service; import org.springframework.stereotype.Service; @Service("HelloWorldService") public class HelloWorldServiceServiceImp implements HelloWorldService { @Override public String sayHello(String name) { return "Hello, " + name; } } </code></pre> <h3>2.3注册service接口到hessian工厂</h3> <pre> <code class="language-java">package net.xqlee.project; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.remoting.caucho.HessianServiceExporter; import net.xqlee.project.service.HelloWorldService; @SpringBootApplication public class DemoSpringbootRpcHessianApplication { @Autowired private HelloWorldService helloWorldService; public static void main(String[] args) { SpringApplication.run(DemoSpringbootRpcHessianApplication.class, args); } // 发布服务 @Bean(name = "/HelloWorldService") public HessianServiceExporter accountService() { HessianServiceExporter exporter = new HessianServiceExporter(); exporter.setService(helloWorldService); exporter.setServiceInterface(HelloWorldService.class); return exporter; } } </code></pre> <br /> 至此服务端编写完毕。<br /> <span style="color:#ff0000"><strong>提示:</strong></span><br /> <span style="color:#ff0000">这里需要一个操作.eclipse中进行右键导出,将接口导出到一个jar包文件,这样也是方便调用方使用。我这里导出并命令为rpc-hessian-demo-interface.jar</span> <p> </p> <h2>三.hessian客服端</h2> <h3>3.1创建一个spring boot项目添加web依赖和hessian依赖</h3> 注意,还需要引入刚才服务端导出的<strong><span style="color:#ff0000">rpc-hessian-demo-interface.jar</span></strong><br /> pom.xml文件: <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project</groupId> <artifactId>demo-springboot-rpc-hessian-client</artifactId> <version>2.0</version> <packaging>jar</packaging> <name>demo-springboot-rpc-hessian-client</name> <description>lee-leftso-v2.0</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.caucho/hessian --> <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.51</version> </dependency> <!-- 本地引入hessian服务端的接口 --> <dependency> <groupId>net.xqlee.project</groupId> <artifactId>rpc-hessian-demo</artifactId> <version>1.0</version> <scope>system</scope> <systemPath>${project.basedir}/lib/rpc-hessian-demo-interface.jar</systemPath> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> <h3>3.2将引入的服务端接口通过hessian实例化</h3> <pre> <code class="language-java">package net.xqlee.project; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.remoting.caucho.HessianProxyFactoryBean; import net.xqlee.project.service.HelloWorldService; @SpringBootApplication public class DemoSpringbootRpcHessianClientApplication { public static void main(String[] args) { SpringApplication.run(DemoSpringbootRpcHessianClientApplication.class, args); } @Bean public HessianProxyFactoryBean helloClient() { HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); factory.setServiceUrl("http://localhost:8083/HelloWorldService"); factory.setServiceInterface(HelloWorldService.class); return factory; } } </code></pre> <h3><br /> 3.3创建一个测试的controller进行调用测试</h3> <pre> <code class="language-java">package net.xqlee.project.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import net.xqlee.project.service.HelloWorldService; @RestController public class DemoHessianController { @Autowired HelloWorldService helloWorldService; @GetMapping("/rpchello.do") public Object rpcSayHello(String name) { return helloWorldService.sayHello(name); } } </code></pre> <br /> 浏览器访问地址:<br /> <img alt="rpc" class="img-thumbnail" src="/resources/assist/images/blog/539bdd2e07d847feb851a8d7513363dc.png" /><br /> <br />  
  • spring boot 入门之整合spring session实现session共享

    spring boot 入门之整合spring session实现session共享。一直以来Java编程中web项目中的session共享问题都是一个很难解决的问题。接下来将讲解通过spring boot整合spring session的方案,将session存入分布式缓存Redis中实现session的共享。<h2>一.前言</h2>   spring boot 入门之整合spring session实现session共享。一直以来Javaweb项目中的session共享问题都是一个很难解决的问题。原因是session是由启动servlet的当前web容器所创建和管理。与其他地方的web容器很难通讯。导致无法共享也就很难实现集群化。这里将通过spring boot整合spring session的方案,将session存入分布式缓存Redis中实现session的共享。 <h2>二.编码</h2> <strong>pom.xml文件:</strong> <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.xqlee.project</groupId> <artifactId>demo-springboot-spring-session</artifactId> <version>1.0</version> <packaging>jar</packaging> <name>demo-springboot-spring-session</name> <description>lee-leftso-v2.0</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> 核心配置类,HttpSessionConfig: <pre> <code class="language-java">package net.xqlee.project.config; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; /** 启用redis session **/ /*** * * @author xqlee maxInactiveIntervalInSeconds设置session超时时间,默认1800秒 */ @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) public class HttpSessionConfig { // spring boot项目可以直接配置application配置文件自动注册redis connect 工厂 // 非boot项目则需要再这里配置一下redis得链接工厂 } </code></pre> <strong>编写一个测试的controller,TestController:</strong> <pre> <code class="language-java">package net.xqlee.project.controller; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("/test.do") public Object testSession(HttpServletRequest request) { Map<String, Object> obj = new HashMap<>(); obj.put("result", true); request.getSession().setAttribute("time", new Date().getTime()); obj.put("time", request.getSession().getAttribute("time")); return obj; } } </code></pre> <p><strong>application配置文件配置redis的链接信息</strong></p> <pre> <code class="language-html">spring.redis.host=10.1.1.2 spring.redis.password= spring.redis.port=6379 </code></pre> <p><span style="color:#0066cc"><strong>具体的redis配置信息根据自己的环境改变</strong></span></p> <h2>三.测试</h2> 启动spring boot项目,注意观察启动日志<br /> <img alt="启动日志" class="img-thumbnail" src="/resources/assist/images/blog/5c72b8f1caff4859b11a60a590bbbf2c.png" /><br /> 从上方日志可以看到springSessionRepositoryFilter已经启用<br /> <br /> 在浏览器中访问测试controller的地址test.do<br /> 通过谷歌浏览器的调试模式可以看到SESSION的cookie<br /> <img alt="cookie" class="img-thumbnail" src="/resources/assist/images/blog/a39e346b5dca4a1493812e9c15793ed4.png" /><br /> 再通过redis的可视化链接工具链接过去查看:<br /> <img alt="session redis" class="img-thumbnail" src="/resources/assist/images/blog/6f5d096243ea4d4d85d53bd83105efa6.png" /><br /> 上图可以看到: <ul> <li>session id和浏览器中的对应;</li> <li>自己添加的time属性;</li> </ul> 到这里spring  boot 整合spring session 通过redis的方式持久化完成。<br /> <br />  
  • Java编程中Spring Boot整合RabbitMQ

    Java编程中Spring Boot整合RabbitMQ实现消息中间件RabbitMQ的使用<p>Java编程中Spring Boot整合RabbitMQ实现消息中间件RabbitMQ的使用<br /> <br />  1 主要用spring-boot-starter-amqp来整合RabbitMQ和SpringBoot</p> <p> 2 pom.xml文件中加入依赖<br />  </p> <pre> <code class="language-xml"> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> <!--<scope>provided</scope>--> </dependency></code></pre> <p> 3编写配置文件application.yml</p> <pre> <code>spring: application: name: rabbitmq-test rabbitmq: host: localhost port: 5672 username: guest password: guest</code></pre> 4 Java编程中编写Sender并使用注解@Component注册为spring框架容器组件 <pre> <code class="language-java">@Component public class Sender { @Autowired private AmqpTemplate amqpTemplate; public void send() throws Exception { String message= "hello" + new Date(); System.out.println("Sender:"+context); this.amqpTemplate.convertAndSend("test_queue_name",message); } }</code></pre> 5 Java编程中编写Reveiver并使用注解@Component注册为spring框架容器组件同时监听队列hello,并用RabbitHandler来处理请求。queues = "test_queue_name"这里的test_queue_name就是发送消息时候的队列名称 <pre> <code class="language-java">@Component @RabbitListener(queues = "test_queue_name") public class Receiver { @RabbitHandler public void process(String message){ System.out.println("Receiver:"+message); } }</code></pre> 6Java编程中编写刚刚用到的hello队列的配置类 <pre> <code class="language-java">@Configuration public class RabbitConfig { @Bean public Queue helloQueue() { return new Queue("test_queue_name"); } }</code></pre> 7 Java编程中编写单元测试类Test,调用Sender的方法发送message,这样Receiver就能自动监听并在主类哪里输出了 <pre> <code class="language-java">@SpringBootTest(classes = Application.class) @RunWith(SpringJUnit4ClassRunner.class) public class Test { @Autowired private Sender sender; @org.junit.Test public void hello() throws Exception { sender.send(); } }</code></pre>
  • spring boot 整合redis实现spring的缓存框架

    spring boot 1.5整合redis实现spring的缓存框架,spring boot,redisspring boot 整合redis实现spring的缓存框架<br /> <br /> 1.创建一个spring boot项目<br /> <img alt="项目" class="img-thumbnail" src="/resources/assist/images/blog/87917c2a16564cc08bf8e7670ec943ea.jpg" /><br /> 2.配置pom.xml文件 <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.leftso</groupId> <artifactId>demo-springboot-redis</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-springboot-redis</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> <br /> 3.在spring boot的application配置文件中配置redis的相关信息 <pre> <code>####################Redis 配置信息 ########################## # Redis数据库分片索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=10.1.1.134 # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=-1 # 连接池中的最大空闲连接 spring.redis.pool.max-idle=8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle=0 # 连接超时时间(毫秒) spring.redis.timeout=0</code></pre> <br /> 4.配置redis整合入spring的缓存框架 <pre> <code class="language-java">package com.leftso.config; import java.lang.reflect.Method; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; @Configuration @EnableCaching // 继承CachingConfigurerSupport并重写方法,配合该注解实现spring缓存框架的启用 public class RedisConfig extends CachingConfigurerSupport { /** 载入通过配置文件配置的连接工场 **/ @Autowired RedisConnectionFactory redisConnectionFactory; @SuppressWarnings("rawtypes") @Autowired RedisTemplate redisTemplate; @Bean RedisTemplate<String, Object> objRedisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } /* * (non-Javadoc) * * @see org.springframework.cache.annotation.CachingConfigurerSupport# * cacheManager() */ @Bean // 必须添加此注解 @Override public CacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate); // 设置缓存过期时间 // redisCacheManager.setDefaultExpiration(60);//秒 return redisCacheManager; } /** * 重写缓存的key生成策略,可根据自身业务需要进行自己的配置生成条件 * * @see org.springframework.cache.annotation.CachingConfigurerSupport# * keyGenerator() */ @Bean // 必须项 @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } } </code></pre> <br /> 5.创建一个测试的pojo和一个测试的controller <pre> <code class="language-java">package com.leftso.pojo; import java.io.Serializable; /** * * <pre> * [Summary] * 测试用简单类型 * [Detail] * TODO * [Author] * XQLEE * [Version] * v1.0 * 2017年5月8日上午9:58:42 * </pre> */ public class Address implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String id; private String city; private String detail; public Address() { } public Address(String id, String city, String detail) { super(); this.id = id; this.city = city; this.detail = detail; } /** * @return the id */ public String getId() { return id; } /** * @param id * the id to set */ public void setId(String id) { this.id = id; } /** * @return the city */ public String getCity() { return city; } /** * @param city * the city to set */ public void setCity(String city) { this.city = city; } /** * @return the detail */ public String getDetail() { return detail; } /** * @param detail * the detail to set */ public void setDetail(String detail) { this.detail = detail; } } </code></pre>   <pre> <code class="language-java">package com.leftso.controller; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.leftso.pojo.Address; @RestController public class CacheTestCtrl { @GetMapping("/getAddr") @Cacheable(value = "address-cache") // 设置缓存的名称,也可以通过key属性指定缓存的key,keyGenerator指定key生成策略器(keyGenerator一般推荐在重写CachingConfigurerSupport类里面的方法适合全局指定) public Address getAddress() { Address addr = new Address("001", "重庆市", "渝北区"); System.out.println("==========你看见这句话表示没有缓存时候打印出来的========"); return addr; } } </code></pre> <br /> 6.启动spring boot项目,访问地址localhost:8080/getAddr<br /> 第一次访问将会在控制台中看到以下输出:<br /> <img alt="1" class="img-thumbnail" src="/resources/assist/images/blog/8273e3645def48cfb209a482857ff0ab.jpg" /><br /> <br /> 后面多次刷新都不会进入到该方法中去读取信息,而是通过缓存直接读取了缓存信息。<br /> <br /> <br /> 至此spring boot整合redis 实现基本的缓存已经完成。
  • spring boot整合mybaties

    spring boot框架整合mybaties数据库暂时选用MySQL<br /> 本博文主要讲解spring boot项目整合mybaties<br /> 1.最终项目结构图<br /> <img alt="结构" class="img-thumbnail" src="/resources/assist/images/blog/e0b0519f-a4be-43fe-aabe-d57927ba82b5.jpg" style="height:564px; width:305px" /><br /> 2.文件清单<br /> 清单:pom.xml <pre> <code class="language-xml"><?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo-springboot-mybaties</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>demo-springboot-mybaties</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!-- mybaties --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> </code></pre> 清单:User.java <pre> <code class="language-java">package com.example.pojo; public class User { private Long id; private String userName; private String userSex; private int userAge; public User() { } public User(String userName, String userSex, int userAge) { super(); this.userName = userName; this.userSex = userSex; this.userAge = userAge; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserSex() { return userSex; } public void setUserSex(String userSex) { this.userSex = userSex; } public int getUserAge() { return userAge; } public void setUserAge(int userAge) { this.userAge = userAge; } } </code></pre> 清单:UserMapper.java <pre> <code class="language-java">package com.example.mapper; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.example.pojo.User; public interface UserMapper { /** * 查询所有用户信息 * * @return */ @Select("select * from user") @Results(value = { @Result(property = "userSex", column = "user_sex", javaType = String.class), @Result(property = "userName", column = "user_name"), @Result(property = "userAge", column = "user_age") }) List<User> findList(); /** * 通过ID查询 * * @param id * @return */ @Select("select * from user u where u.id=#{id}") User findOne(@Param("id") Long id); /** * 新增一个 * * @param user */ @Insert("insert into user (user_name,user_sex,user_age) values(#{userName},#{userSex},#{userAge})") void insert(User user); /** * 修改 * * @param user */ @Update("update user u set u.user_name=#{userName},u.user_sex=#{userSex},u.user_age=#{userAge} where u.id=#{id}") void update(User user); /** * 删除 * * @param id */ @Delete("delete from user where id=#{id}") void delete(@Param("id") Long id); } </code></pre> 清单:UserController.java <pre> <code class="language-java">package com.example.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.example.mapper.UserMapper; import com.example.pojo.User; @RestController public class UserController { @Autowired UserMapper userMapper; /** * index * * @return */ @RequestMapping("/") public String index() { return "User Info By Mybaties"; } @RequestMapping("/user/list.json") public Object allUsers() { List<User> users = userMapper.findList(); return users; } } </code></pre> 清单:Application.java <pre> <code class="language-java">package com.example; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @MapperScan(basePackages = { "com.example.mapper" }) // 自动扫描mapper @EnableTransactionManagement//启用事物管理,在service上使用@Transactional(注意是spring的 注解) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } </code></pre> 清单:application.properties <pre> <code class="language-perl">#==================DataSource Config Start================== #name #spring.datasource.name=test #url #spring.datasource.url=jdbc:sqlserver://192.168.xxx.xxx;instanceName=sql_03;DatabaseName=edu;integratedSecurity=false spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8 #DriverClass #spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver spring.datasource.driver-class-name=com.mysql.jdbc.Driver #DB username spring.datasource.username=root #DB password spring.datasource.password=root #==================DataSource Config End================== #==================mybaties Config Start================== #ORM Bean Package mybatis.type-aliases-package=com.example.pojo mybatis.mapper-locations=classpath:/mapper/*.xml #打印mybatiesSql语句 logging.level.com.example.mapper=DEBUG #==================mybaties Config End ================== </code></pre> 清单:UserMapperTest.java <pre> <code class="language-java">package com.example.test; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import com.example.mapper.UserMapper; import com.example.pojo.User; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest { @Autowired private UserMapper userMapper; // @Test public void testInsert() { try { userMapper.insert(new User("xqlee1", "男", 26)); userMapper.insert(new User("xqlee2", "男", 23)); userMapper.insert(new User("xqlee3", "男", 27)); } catch (Exception e) { e.printStackTrace(); } } // @Test public void testUpdate() { try { User user = new User("测试0000", "男", 23); user.setId(1l); userMapper.update(user); } catch (Exception e) { e.printStackTrace(); } } //@Test public void testQuery() { try { List<User> users=userMapper.findList(); for(User u:users){ System.out.println("ID:"+u.getId()+" Name:"+u.getUserName()+" Sex:"+u.getUserSex()+" Age:"+u.getUserAge()); } } catch (Exception e) { e.printStackTrace(); } } @Test public void testDelete(){ try { userMapper.delete(1l); testQuery(); } catch (Exception e) { e.printStackTrace(); } } } </code></pre>