• SpringBoot学习笔记


    SpringBoot

    一、SpringBoot的简介

    1.1 SpringBoot产生的背景

    Spring 框架的常见问题是要快速创建一个可以运行的应用比较麻烦,对于新接触 Spring 框架的开发人员来说,并不知道如何更好的使用这些组件。

    Spring Boot 是 Spring 框架的一个新的子项目,用于创建 Spring 4.0 项目。它的开发始于 2013 年。2014 年 4 月发布 1.0.0 版本。它可以自动配置 Spring 的各种组件,并不依赖代码生成和 XML 配置文件。Spring Boot 也提供了对于常见场景的推荐组件配置。Spring Boot 可以大大提升使用 Spring 框架时的开发效率

    Ø 使用Spring boot ,可以轻松的创建独立运行的程序,非常容易构建独立的服务组件,是实现分布式架构、微服务架构利器。

    Ø Spring boot简化了第三方包的引用,通过提供的starter,简化了依赖包的配置。

    1.2 SpringBoot的优缺点

    Ø 轻松创建独立的Spring应用程序。

    Ø 内嵌Tomcat、jetty等web容器,不需要部署WAR文件。

    Ø 提供一系列的“starter” 来简化的Maven配置,不需要添加很多依赖

    Ø 开箱即用,尽可能自动配置Spring。

    NameServlet VersionJava Version
    Tomcat 8 3.1 Java 7+
    Tomcat 7 3.0 Java 6+
    Jetty 9.3 3.1 Java 8+
    Jetty 9.2 3.1 Java 7+
    Jetty 8 3.0 Java6+

    二、SpringBoot入门案例

    Step01:

    解压一个maven3.5到本地

    Step02:

    修改maven的confsetting的本地仓库存储路径

    Step03:

    修改maven的confsetting 中远程仓库为阿里云的

    Step04:

    把Eclipse中的本地和全局的仓库文件都改成confsetting

    Step05:

    创建一个 maven war项目(test1)或创建一个 maven jar(test2)。 这两种都可以,但一般都使用jar,因为spring是用于服务,不建议与jsp使用

    +springbootdemo1 pom.xml

    +springbootdemo2 pom.xml

    Step06:

    在pom.xml添加spring-boot-starter-web依赖,如图

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    spring-boot-starter-parent作用:

    在pom.xml中引入spring-boot-start-parent,它可以提供dependency management,也就是说依赖管理引入以后在申明其它dependency的时候就不需要version了,后面可以看到。

    spring-boot-starter-web作用:springweb 核心组件

    Step07:

    写一个控制器如下,然后写一个main方法,把程序跑起来:

    package com.jihaiyang.web.controller;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
    ​
    @RestController//相当于声明Controller - 提共restful 风格
    @EnableAutoConfiguration//自动配置,不需要写spring的配置文件
    class HelloController {
    ​
        @RequestMapping(value = "hello/{name}")
        public String hello1(@PathVariable("name") String name){
            return name+"Hello,SpringBoot";
        }
        public static void main(String[] args) {
            SpringApplication.run(HelloController.class);//启动当前控制器
        }
    }

    Step08:

    在浏览器中访问http://localhost:8080/hello

    三、SpringBoot的两种启动方式

    3.1 在每个控制器中启动

    在控制器配置@EnableAutoConfiguration并使用SpringApplication.run()启动程序

    3.2 创建一个App类

    创建一个App类,在App类中配置@EnableAutoConfiguration和组件扫描ComponentScan,

    然后使用SpringApplication启动程序,这样就可以访问多个Controller了.

    @RequestMapping("{id}")
    @ResponseBody
    public User userInfo(@PathVariable(varlue="id") Integer id)
    {
        User user=new User("gyf","123");
        return user;
    }

    创建App类

    @ComponentScan(basePackages="com.jihaiyang.web.controller")//controller所在的包进行扫描
    @EnableAutoConfiguration//此处只需写一个,其他控制器不用写了
    public class App{
        public static void main(String[] args){
            SpringApplication.run(App.class,args);
        }
    }

    四、SpringBoot的Starter Project Options介绍

    spring-boot-starter核心 POM,包含自动配置支持、日志库和对 YAML 配置文件的支持
    spring-boot-starter-amqp 通过 spring-rabbit 支持 AMQP
    spring-boot-starter-aop 包含 spring-aop 和 AspectJ 来支持面向切面编程(AOP)。
    spring-boot-starter-batch 支持 Spring Batch,包含 HSQLDB。
    spring-boot-starter-data-jpa 包含 spring-data-jpa、spring-orm 和 Hibernate 来支持 JPA。
    spring-boot-starter-data-mongodb 包含 spring-data-mongodb 来支持 MongoDB。
    spring-boot-starter-data-rest 通过 spring-data-rest-webmvc 支持以 REST 方式暴露 Spring Data 仓库。
    spring-boot-starter-jdbc 支持使用 JDBC 访问数据库
    spring-boot-starter-security 包含 spring-security。
    spring-boot-starter-test 包含常用的测试所需的依赖,如 JUnit、Hamcrest、Mockito 和 spring-test 等。
    spring-boot-starter-velocity 支持使用 Velocity 作为模板引擎。
    spring-boot-starter-web 支持 Web 应用开发,包含 Tomcat 和 spring-mvc。
    spring-boot-starter-websocket 支持使用 Tomcat 开发 WebSocket 应用。
    spring-boot-starter-ws 支持 Spring Web Services
    spring-boot-starter-actuator 添加适用于生产环境的功能,如性能指标和监测等功能。
    spring-boot-starter-remote-shell 添加远程 SSH 支持
    spring-boot-starter-jetty 使用 Jetty 而不是默认的 Tomcat 作为应用服务器。
    spring-boot-starter-log4j 添加 Log4j 的支持
    spring-boot-starter-logging 使用 Spring Boot 默认的日志框架 Logback
    spring-boot-starter-tomcat 使用 Spring Boot 默认的 Tomcat 作为应用服务器。

    spring-boot-starter-web

    Ø POM 文件中可以看到,应用所声明的依赖很少

    Ø 只有一个“org.springframework.boot:spring-boot-starter-web”

    Ø 而不是像其他 Spring 项目一样需要声明很多的依赖。

    Ø 当使用 Maven 命令“mvn dependency:tree”来查看项目实际的依赖时

    Ø 发现其中包含SpringMVC框架、SLF4J、Jackson、Hibernate Validator 和 Tomcat 等依赖。

    Ø 这实际上 Spring 推荐的 Web 应用中使用的开源库的组合。

    EnableAutoConfiguration

    Ø EnableAutoConfiguration”注解的作用在于让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置,这就减少了开发人员的工作量。

    Ø Spring Boot 推荐采用基于 Java 注解的配置方式,而不是传统的 XML。只需要在主配置 Java 类上添加“@EnableAutoConfiguration”注解就可以启用自动配置。

    Ø 注解“@RestController”和”@RequestMapping”由 Spring MVC 提供,用来创建 REST 服务。这两个注解和 Spring Boot 本身并没有关系。

    五、Web开发

    5.1 静态资源的访问

    在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。

    Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则:

    /static

    /public

    /resources

    /META-INF/resources

    举例:我们可以在src/main/resources/目录下创建static/imgs,在该位置放置一个图片文件。启动程序后,尝试访问http://localhost:8080/imgs/d.jpg,访问时不用加static目录。如能显示图片,配置成功。

    5.2 控制器返回JSON格式数据

    @RestController
    public class UserController{
        @RestMapping("/login")
        @ResponseBody
        public Map<String,Object> login(Sring username,String password){
            Map<String,Object> map=new HashMap<String,Object>();
            if("季海洋".equals(username) && "123".equal(password)){
                map.put("status",true);
                map.put("info","登陆成功");
            }else{
                map.put("status",false);
                map.put("info","用户名或密码错误");
            }
            return map;
        }
    }

    5.3 全局捕获异常

    @ExceptionHandler 表示拦截异常。@ControllerAdvicecontroller 的一个辅助类,最常用的就是作为全局异常处理的切面类,可以指定扫描范围,约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用

    @ResponseBody 进行 json 转换。

    @ControllerAdvice//切面
    public class GlobalExceptionHandler {
        @ExceptionHandler(RuntimeException.class)//捕获运行时异常
        @ResponseBody
        public Map<String,Object> exceptionHander(){
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("status",false);
            map.put("info","系统异常");
            return map;
        }
    }

    在启动spring中,配置扫描包为com.jihaiyang.web

    @ComponentScan(basePackages="com.jihaiyang.web")
    @EnableAutoConfiguration
    public class App{
        public static void main(args){
            SpringApplication.run(App.class,args);
        }
    }

    在某个映射的方法中添加个int i=10/0的算术异常

    @RestController
    public class UserController{
        @RequestMapping("/login")//映射路径
        @ResponseBody//响应体-自动返回json格式字符串
        public Map<String,Object> login(String username,String password){
            int i=10/0;
            Map<String,Object> map=new HashMap<String,Object>();
            if("jihaiyang".equals(username) && "123".equals(password)){
                map.put("status",true);
                map.put("info","登录成功!");
            }else{
                map.put("status",false);
                map.put("info","登录失败!");
            }
            return map;
        };
    }

    5.4、渲染Web页面

    模板引擎

    在动态HTML实现上Spring Boot依然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板引擎下,我们可以很快的上手开发动态网站。

    Spring Boot提供了默认配置的模板引擎主要有以下几种:

    1 Thymeleaf

    2 FreeMarker

    3 Velocity

    4 Groovy

    5 Mustache

    Springboot+freemarker

    Spring Boot建议使用这些模板引擎,避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性,具体可见后文:支持JSP的配置

    当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates。当然也可以修改这个路径,具体如何修改,可在后续各模板引擎的配置属性中查询并修改。

    5.5 Freemarker的使用

    5.5.1:引入freeMarker的依赖包

    <!-- 引入freeMarker的依赖包. -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency> 

    5.5.2:写个控制器,并返回些数据

    @Controller//如果访问freemarker模板,就不要用RestController
    @RequestMapping("/stu")
    public class StudentController{
        @RequestMapping("/list")
        public String list(Map data){
            HashMap data=new HashMap();
            //添加数据
            data.put("loginname","jihaiyang");
            data.put("age",32);
            ArrayList arrayList = new ArrayList();
            String[][] strings = {
                new String[]{"1001","张三","男"},
                new String[]{"1002","李四","男"},
                new String[]{"1003","王五","男"},
                new String[]{"1004","赵六","男"}
            };
            for (String[] string : strings) {
                HashMap hashMap = new HashMap();
                hashMap.put("id",string[0]);
                hashMap.put("name",string[1]);
                hashMap.put("gender",string[2]);
                arrayList.add(hashMap);
            }
            data.put("stuList",arrayList);
            return "stu/list";
        }
    }

    5.5.3:创建.ftl模板文件

    Ø 在src/main/resources/创建一个templates/stu文件夹,后缀为*.ftl

    Ø 掌握如何取值和判断

    list.ftl文件

    <!DOCTYPE html>
    <html>
        <head lang="en">
            <meta   charset="UTF-8" />
            <title></title>
        </head>
        <body>
            欢迎${loginname}
            <#if age <= 17>小哥
                <#elseif age <= 30>先生
                <#else>大叔
            </#if>登录
            <table border="1">
                <tr>
                    <td>ID</td>
                    <td>名字</td>
                    <td>性别</td>
                </tr>
                <#list   stuList?sort_by("id")?reverse as stu>
                    <tr>
                        <td>   ${stu.id}</td> 
                        <td>   ${stu.name}</td>
                        <td>   ${stu.gender}</td>
                    </tr>
                 </#list>
            </table>
        </body>
    </html>   

    5.6 SpringBoot 使用jsp

    Step1:创建war maven工程

    Step2:pom文件引入以下依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
    </parent>
    <dependencies>
        <!-- SpringBoot 核心组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
    </dependencies>

    Step3:application.properties创建以下配置

    spring.mvc.view.prefix=/WEB-INF/view/
    spring.mvc.view.suffix=.jsp 

    Step4:控制器代码

    @Controller
    @EnableAutoConfiguration
    @RequestMapping("/teacher")
    public class TeacherController{
        @RequestMapping("/list")
        public String list(){
            return "list";
        }
        
        public static void main(String[] args){
            SpringApplication.run(TeacherController.class,args);
        }
    }

    Step5:jsp

    application.properties中设置内容如下

    spring.mvc.view.prefix=/WEB-INF/view/
    spring.mvc.view.suffix=.jsp

    六、数据库访问

    6.1 SpringBoot使用JDBC

    Step1:添加依赖

    <!-- JDBC -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <!-- 数据库驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    Step2:application.properties新增配置

    #视图配置
    spring.mvc.view.prefix=/WEB-INF/view/
    spring.mvc.view.suffix=.jsp
    #数据库配置
    spring.datasource.url=jdbc:mysql://localhost:3306/day12
    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver

    Step3:Service

    在com.jihaiyang.service.impl中编写

    @Service
    private void registerUser(String username,String password,String email){
        @Autowired
        private JdbcTemplate jdbcTemplate;
        String sql ="insert into user(username,password,email) values(?,?,?)"; 
        jdbcTemplate.update(sql,username,password,email);
    }

    Step4:Controller

    在com.jihaiyang.web.controller编写

    @Controller
    @RequestMapping("/user")
    public class UserController{
        @Autowire
        IUservice userService;
        
        @RequestMapping("/register")
        @ResponseBody
        public String register(){
            userService.registerUser("root","root","root");
            return "success";
        }
    }

    Step5:App

    在com.jihaiyang.app中编写

    @ComponentScan(basePackage={"com.jihaiyang.web","com.jihaiyang.service"})
    @EnableAutoConfiguration
    public class App{
        public static void main(String[] args){
        SpringApplication.run(App.class,args) ;   
        }
    }

    6.2 使用Mybatis

    6.2.1 创建一个maven-jar新项目来讲解

    6.2.2 pom导入

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.3.2.RELEASE</version>
            <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <!-- 单元测试 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!-- mybaties -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> 
                </dependency>
        </dependencies>

    6.2.3 数据库配置文件

    application.properties文件的配置如下

    #数据库配置
    spring.datasource.url=jdbc:mysql://localhost:3306/
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver

    6.2.4 Mapper

    com.jihaiyang.Mapper中编写Mapper接口

    public interface UserMapper{
        @Insert("insert into user(username,password) values(#{username},#{password}")
        public void save(@Param("username") String username,@Param("password") String password)
            @Select("select * from user where username=#{username}")
            public User findByUsername(@Param("username") String username);
    }

    ※※※※※※※※※※※※

    换成xml形式,将这个放入Maper包中

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.jihaiyang.mapper.UserMapper" ><insert id="save">
            insert into t_user (username,password) VALUES(#{0},#{1})
        </insert>
        <select id="findByUsername" resultType="com.gyf.model.User" parameterType="string">
            select * from t_user where username = #{username,jdbcType=VARCHAR}
        </select>
    </mapper>

    注意这里需要在pom中添加下面代码

    <build>
      <resources>
        <resource>
          <directory>src/main/java</directory>
          <includes>
            <include>**/*.xml</include>
          </includes>
        </resource>
      </resources>
    </build>

    ※※※※※※※※※※※※

    6.2.4 Controller

    package com.jihaiyang.controller;
    ​
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import com.gyf.mapper.UserMapper;
    import com.gyf.model.User;
    ​
    @Controller
    @RequestMapping("/user")
    public class UserController {
    ​
        @Autowired
        private UserMapper userMapper;
        @RequestMapping("/find")
        @ResponseBody
        public User find(String name){
            return userMapper.findByName(name);
        }
        
        @ResponseBody
        @RequestMapping("/add")
        public int add(String name){
            return userMapper.insert(name,"e10adc3949ba59abbe56e057f20f883e");
        }
    }

    6.2.5 App

    package com.jihaiyang.app;
    ​
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.context.annotation.ComponentScan;
    ​
    @ComponentScan(basePackages={"com.gyf.controller"})
    @MapperScan(basePackages={"com.gyf.mapper"})//扫描Mapper
    @EnableAutoConfiguration
    public class App {
        public static void main(String[] args) {
            SpringApplication.run(App.class, args);
        }
    }

    6.3 spring 中使用的事务

    只需要加个Transactional注解即可

    @Transaction
    public class UserServiceImpl implements IUserService{
        @Autowired
        private UserMapper userMapper;
        @Override
        public void register(String username,String password){
            userMapper.save(username,password);
            int i=10/0;
        }
    }

    6.4 配置多数据源

    以前是在applicationContext.xml中配置数据源,现在我们通过注解来配置数据源,在com.jihaiyang包下创建包datasource

    6.4.1 配置文件中新增两个数据源所需的参数

    spring.datasource.test1.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.test1.url=jdbc:mysql://localhost:3306/dbfirst?useUnicode=true&characterEncoding=utf-8
    spring.datasource.test1.username=root
    spring.datasource.test1.password=123456
    ​
    spring.datasource.test2.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.test2.url=jdbc:mysql://localhost:3306/dbsecond?useUnicode=true&characterEncoding=utf-8
    spring.datasource.test2.username=root
    spring.datasource.test2.password=123456

    数据库SQL语句如下

    use dbone;
    CREATE table user(
        id  int PRIMARY KEY AUTO_INCREMENT,
      username VARCHAR(50),
        password VARCHAR(50),
        email VARCHAR(50),
      birthday TIMESTAMP
    );
    ​
    use dbsecond;
    CREATE table customer(
        id  int PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(50),
        tel VARCHAR(50)
    );
    ​

    6.4.2 编写数据源配置类

    dbone数据库的数据源配置信息

    @Configuration//注解到springboot容器中
    @MapperScan(basePackages="com.jihaiyang.dbFirst.mapper",sqlSessionFactoryRef="dbFirstSqlSessionFactory")
    public class DataSource01 {
    ​
        /**
         * @return 返回dbFirst数据库的数据源
         */
        @Bean(name="dbFirstDataSource")
        @Primary//主数据源
        @ConfigurationProperties(prefix="spring.datasource.dbFirst")
        public DataSource dateSource(){
            return DataSourceBuilder.create().build();
        }
    ​
        /**
         * @return 返回dbFirst数据库的会话工厂
         */
        @Bean(name = "dbFirstSqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("dbFirstDataSource") DataSource ds) throws Exception{
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(ds);
    ​
            return bean.getObject();
        }
    ​
        /**
         * @return 返回dbFirst数据库的事务
         */
        @Bean(name = "dbFirstTransactionManager")
        @Primary
        public DataSourceTransactionManager transactionManager(@Qualifier("dbFirstDataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    ​
        /**
         * @return 返回dbFirst数据库的会话模版
         */
        @Bean(name = "dbFirstSqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(
                @Qualifier("dbFirstSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }

    dbtwo数据库的数据源配置信息

    @Configuration//注解到springboot容器中
    @MapperScan(basePackages = "com.jihaiyang.dbSecond.mapper", sqlSessionFactoryRef = "dbSecondSqlSessionFactory")
    public class DataSource02 {
    ​
        /**
         * @return 返回dbSecond数据库的数据源
         */
        @Bean(name = "dbSecondDataSource")
        @ConfigurationProperties(prefix = "spring.datasource.dbSecond")
        public DataSource dateSource() {
            return DataSourceBuilder.create().build();
        }
    ​
        /**
         * @return 返回dbSecond数据库的会话工厂
         */
        @Bean(name = "dbSecondSqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("dbSecondDataSource") DataSource ds) throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(ds);
    ​
            return bean.getObject();
        }
    ​
        /**
         * @return 返回dbSecond数据库的事务
         */
        @Bean(name = "dbSecondTransactionManager")
        public DataSourceTransactionManager transactionManager(@Qualifier("dbSecondDataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    ​
        /**
         * @return 返回dbSecond数据库的会话模版
         */
        @Bean(name = "dbSecondSqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(
                @Qualifier("dbSecondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }

    6.4.3 dbSecond mapper & service

    public interface CustomerMapper{
        @Insert("insert into customer(name,phone) values(#{name},#{telphone})")
        int insert(@Param("name") String name,@Param("telphone") String telphone)
    }
    
    @Service
    public class CustomerService{
        @Autowired
        private CustomerMapper customerMapper;
        /*
        *添加一个客户
        */
        public void add(String name,String telphone){
            customerMapper.insert(name,telphone);
        }
    }

    6.4.4 Controller

    @Controller
    @RequestMapper("/user")
    public class UserController{
        @Autowired
        private UserService userservice;
        @Autowired
        private CustomerService customerService;
        
        @ResponseBody
        @RequestMapping("/add")
        public String add(String name){
            userService.register(name,"123");
            customerService.add(name,"110");
            return "success";
        }
    }

    6.4.5 App

    @ComponentScan(basePackages={"com.jihaiyang.datasource","com.jihaiyang.dbone","com.jihaiyang.dbtwo"})
    @EnableAutoConfiguration
    public class App{
        public static void main(String[] args){
            SpringApplication.run(App.class,args)
        }
    }

    6.5 多数据源问题

    验证代码就不敲了,结论是一个事务只对当前的数据源有效。

    6.6 springboot中的多事务管理

    使用springboot+jta+atomikos 分布式事物管理解决方案

    6.6.1 添加jta依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jta-atomikos</artifactId>
    </dependency>

    6.6.2 修改数据库连接配置数据

    # Mysql 1
    mysql.datasource.dbfirst.url = jdbc:mysql://localhost:3306/dbone?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.dbfirst.username = root
    mysql.datasource.dbfirst.password = 123456
    ​
    mysql.datasource.dbfirst.minPoolSize = 3
    mysql.datasource.dbfirst.maxPoolSize = 25
    mysql.datasource.dbfirst.maxLifetime = 20000
    mysql.datasource.dbfirst.borrowConnectionTimeout = 30
    mysql.datasource.dbfirst.loginTimeout = 30
    mysql.datasource.dbfirst.maintenanceInterval = 60
    mysql.datasource.dbfirst.maxIdleTime = 60
    ​
    mysql.datasource.dbfirst.testQuery = select 1
    # Mysql 2
    mysql.datasource.dbsecond.url =jdbc:mysql://localhost:3306/dbsecond?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.dbsecond.username =root
    mysql.datasource.dbsecond.password =123456
    mysql.datasource.dbsecond.minPoolSize = 3
    mysql.datasource.dbsecond.maxPoolSize = 25
    mysql.datasource.dbsecond.maxLifetime = 20000
    mysql.datasource.dbsecond.borrowConnectionTimeout = 30
    mysql.datasource.dbsecond.loginTimeout = 30
    mysql.datasource.dbsecond.maintenanceInterval = 60
    mysql.datasource.dbsecond.maxIdleTime = 60
    mysql.datasource.dbsecond.testQuery = select 1

    6.6.3 添加2个配置模型

    模型放在com.jihaiyang.dbconfig包 dbFirst数据源模型

    @ConfigurationProperties("mysql.datasource.dbfirst")
    public class DBConfig1 {
        private String url;
        private String username;
        private String password;
        private int minPoolSize;
        private int maxPoolSize;
        private int maxLifetime;
        private int borrowConnectionTimeout;
        private int loginTimeout;
        private int maintenanceInterval;
        private int maxIdleTime;
        private String testQuery;
    }

    dbSecond数据源模型

    @ConfigurationProperties("mysql.datasource.dbsecond")
    public class DBConfig2 {
        private String url;
        private String username;
        private String password;
        private int minPoolSize;
        private int maxPoolSize;
        private int maxLifetime;
        private int borrowConnectionTimeout;
        private int loginTimeout;
        private int maintenanceInterval;
        private int maxIdleTime;
        private String testQuery;
    }

    6.6.4 设定两个数据源具体的参数

    dbfirst数据库的数据源

    package com.jihaiyang.datasource;
    ​
    import java.sql.SQLException;
    import javax.sql.DataSource;
    ​
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    ​
    import com.atomikos.jdbc.AtomikosDataSourceBean;
    import com.jihaiyang.dbconfig.DBConfig1;
    import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
    ​
    @Configuration//注解到springboot容器中
    @MapperScan(basePackages = "com.jihaiyang.dbFirst.mapper", sqlSessionFactoryRef = "dbFirstSqlSessionFactory")
    public class DataSource01 {
    ​
        // 配置数据源
        @Primary
        @Bean(name = "dbFirstDataSource")
        public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
            MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
            mysqlXaDataSource.setUrl(testConfig.getUrl());
            mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
            mysqlXaDataSource.setPassword(testConfig.getPassword());
            mysqlXaDataSource.setUser(testConfig.getUsername());
            mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    ​
            AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(mysqlXaDataSource);
            xaDataSource.setUniqueResourceName("dbFirstDataSource");
    ​
            xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
            xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
            xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
            xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
            xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
            xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
            xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
            xaDataSource.setTestQuery(testConfig.getTestQuery());
            return xaDataSource;
        }
    ​
        @Bean(name = "dbFirstSqlSessionFactory")
        public SqlSessionFactory testSqlSessionFactory(@Qualifier("dbFirstDataSource") DataSource dataSource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            return bean.getObject();
        }
    ​
        @Bean(name = "dbFirstSqlSessionTemplate")
        public SqlSessionTemplate testSqlSessionTemplate(
                @Qualifier("dbFirstSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }
    

    dbsecond数据库的数据源

    package com.jihaiyang.datasource;
    import java.sql.SQLException;
    import javax.sql.DataSource;
    ​
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    ​
    import com.atomikos.jdbc.AtomikosDataSourceBean;
    import com.gyf.dbconfig.DBConfig2;
    import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
    ​
    @Configuration//注解到springboot容器中
    @MapperScan(basePackages = "com.gyf.dbSecond.mapper", sqlSessionFactoryRef = "dbSecondSqlSessionFactory")
    public class DataSource02 {
    ​
        // 配置数据源
        @Bean(name = "dbSecondDataSource")
        public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
            MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
            mysqlXaDataSource.setUrl(testConfig.getUrl());
            mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
            mysqlXaDataSource.setPassword(testConfig.getPassword());
            mysqlXaDataSource.setUser(testConfig.getUsername());
            mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    ​
            AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(mysqlXaDataSource);
            xaDataSource.setUniqueResourceName("dbSecondDataSource");
    ​
            xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
            xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
            xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
            xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
            xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
            xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
            xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
            xaDataSource.setTestQuery(testConfig.getTestQuery());
            return xaDataSource;
        }
    ​
        @Bean(name = "dbSecondSqlSessionFactory")
        public SqlSessionFactory testSqlSessionFactory(@Qualifier("dbSecondDataSource") DataSource dataSource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            return bean.getObject();
        }
    ​
        @Bean(name = "dbSecondSqlSessionTemplate")
        public SqlSessionTemplate testSqlSessionTemplate(
                @Qualifier("dbSecondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }

    七 整合Log4j

    7.1 导入Log4j属性文件

    log4j.properties

    注意,复制时要把每一行后面的空格去除

    log4j.rootLogger=INFO,Console,File   
    log4j.appender.Console=org.apache.log4j.ConsoleAppender  
    log4j.appender.Console.Target=System.out
    log4j.appender.Console.layout=org.apache.log4j.PatternLayout  
    log4j.appender.Console.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c - %L]%m%n
     
    log4j.appender.File=org.apache.log4j.RollingFileAppender  
    log4j.appender.File.File=C:/Users/10301/Desktop/test/logs/info/info.log 
    log4j.appender.File.MaxFileSize=10MB  
     
    log4j.appender.File.Threshold=ALL  
    log4j.appender.File.layout=org.apache.log4j.PatternLayout  
    log4j.appender.File.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c - %L]%m%n 

    7.2 pom.xml

    去除springboot的logging,添加log4j,因为自带的logging不启效果

    springboot下的Log4j的版本最新1.3.8,如果你的springboot的parent版本过高,那在在添加log4j自己版本 。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <exclusiions>
            <exclusion>
                <groupID>org.springframework.boot</groupID>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusiions>
    </dependency>

    添加自己的log4j版本

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j</artifactId>
        <version>1.3.8 RELEASE</version>
    </dependency>

    7.3 测试

    @Autowired
    private UserService userService;
    Logger logger=Logger.getLogger(UserService.class);
    @ResponseBody
    @RequestMapping("/add")
    public String add(String name){
        logger.info("this is test information !"+"@@Hello :"+name);
        return "success";
    }

    8. 使用AOP统一处理Web请求日志

    Step01

    <!-- AOP -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    Step02:写个切面类

    package com.jihaiyang.aop;
    ​
    import java.util.Enumeration;
    ​
    import javax.servlet.http.HttpServletRequest;
    ​
    import org.apache.log4j.Logger;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    @Aspect
    @Component
    public class WebLogAspect {
        private Logger logger = Logger.getLogger(getClass());
        
        @Pointcut("execution(public * com.gyf.controller..*.*(..))")
        public void webLog() {
        
        }
        
        @Before("webLog()")
        public void doBefore(JoinPoint joinPoint) throws Throwable {
            // 接收到请求,记录请求内容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 记录下请求内容
            logger.info("---------------request----------------");
            logger.info("URL : " + request.getRequestURL().toString());
            logger.info("HTTP_METHOD : " + request.getMethod());
            logger.info("IP : " + request.getRemoteAddr());
            Enumeration<String> enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String name = (String) enu.nextElement();
                logger.info("name:" + name + "value" + request.getParameter(name));
            }
        }
        @AfterReturning(returning = "ret", pointcut = "webLog()")
        public void doAfterReturning(Object ret) throws Throwable {
            logger.info("---------------response----------------");
            // 处理完请求,返回内容
            logger.info("RESPONSE : " + ret);
        }
    }

    Step3:App

    在App类中添加对该AOP类的扫描

    8. 修改端口号

    在application.properties中

    server.port=8888 
    server.context-path=/test

    在application.yml中

    注意冒号后的只能用空格,不能用tab

    server:
      port:  8090
      context-path: /test-yml

    Springboot 打包部署

    1. 先打成war包或者jar包

    2. 使用java -jar test3-0.0.1-SNAPSHOT.jar 运行即可

    打包时添加下面依赖代码

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.gyf.app.App</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    在终端要停止服务器时,使用Ctrl + C。直接点x,会端口没有关掉。

  • 相关阅读:
    【设计模式】6.模板方法模式
    【设计模式】5.原型模式
    【设计模式】4.工厂模式
    【设计模式】3.代理模式
    zookeeper集群的搭建
    zookeeper实现分布式锁的原理和一个小例子
    zookeeper配置管理实现原理----监听事件watch
    zookeeper的javaAPI操作(基于Curator的CRUD)
    java.lang.IllegalArgumentException: A HostProvider may not be empty!
    Zookeeper的安装和基本操作
  • 原文地址:https://www.cnblogs.com/kitor/p/11272660.html
Copyright © 2020-2023  润新知