1. 程式人生 > >springboot 2.0.3.RELEASE + druid 1.1.10 多資料來源(可用讀寫分離) + mysql + ssm搭建

springboot 2.0.3.RELEASE + druid 1.1.10 多資料來源(可用讀寫分離) + mysql + ssm搭建

開始,先上一張專案總體圖片:

1、springboot熱部署中idea配置、怎樣一步一步搭建就不說了。

2、用到的技術點:springboot全域性異常處理,springboot熱部署,aop,ssm,mysql,druid sql監控,druid多資料來源切換(可以做讀寫分離)。

3、下面開始上程式碼了:

①:DbConfig
package com.yzw.waldron.wenjing.config;

import com.yzw.waldron.wenjing.db.DataSourceAspect;
import org.springframework.context.annotation.Bean
; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; @Configuration @ImportResource({"classpath:config/spring-mybatis.xml"}) public class DbConfig { /** * 資料來源主從切換控制 * * @return */ @Bean public DataSourceAspect getDataSourceAspect() { return new
DataSourceAspect(); } }

②:DruidConfig

package com.yzw.waldron.wenjing.config;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import 
org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class DruidConfig { /** * 註冊一個StatViewServlet * * @return */ @Bean public ServletRegistrationBean druidStatViewServlet() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); //新增初始化引數:initParams //白名單: servletRegistrationBean.addInitParameter("allow", "127.0.0.1"); //IP黑名單 (存在共同時,deny優先於allow) : 如果滿足deny的話提示:Sorry, you are not permitted to view this page. servletRegistrationBean.addInitParameter("deny", "192.168.1.73"); //登入檢視資訊的賬號密碼. servletRegistrationBean.addInitParameter("loginUsername", "admin"); servletRegistrationBean.addInitParameter("loginPassword", "123456"); //是否能夠重置資料. servletRegistrationBean.addInitParameter("resetEnable", "false"); return servletRegistrationBean; } /** * 註冊一個:filterRegistrationBean * * @return */ @Bean public FilterRegistrationBean druidStatFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); //新增過濾規則. filterRegistrationBean.addUrlPatterns("/*"); //新增不需要忽略的格式資訊. filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); return filterRegistrationBean; } }

③:DataSourceAnnot

package com.yzw.waldron.wenjing.db;

import java.lang.annotation.*;

/**
* @Description:      資料來源註解,註解在service實現類的方法上
* @Auther:           Waldron Ye
* @CreateDate:       2018/7/8 9:39
* @Version:          1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DataSourceAnnot {
   DataSourceType value() default DataSourceType.Master;
}

④:DataSourceAspect

package com.yzw.waldron.wenjing.db;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;

import java.lang.reflect.Method;

@Aspect
public class DataSourceAspect implements Ordered {

   private static String REGEX = "select.*List.*|count.*|find.*|query.*|get.*|list.*";

   /** 切入點 */
@Pointcut("execution(* com.yzw.waldron.wenjing..user.dao..*(..))")
// @Pointcut("execution(* com.yzw.waldron.user.service..*(..))")
private void pointcut() {
   }

   @Before(value = "pointcut()")
   public void before(JoinPoint point) {
      Object target = point.getTarget();
      String method = point.getSignature().getName();
      MethodSignature methodSignature = (MethodSignature) point.getSignature();
      Class<?>[] parameterTypes = methodSignature.getMethod().getParameterTypes();
      try {
         Method m = target.getClass().getMethod(method, parameterTypes);
         if (m == null) {
            return;
         }
         DataSourceAnnot data = m.getAnnotation(DataSourceAnnot.class);
         if (m.isAnnotationPresent(DataSourceAnnot.class)) {
            DataSourceHolder.clearType();
            DataSourceHolder.setType(data.value().getName());
            return;
         }
         // 如果無DataSource註解,按方法名字選擇資料來源
if (m.getName().matches(REGEX)) {
            DataSourceHolder.setType(DataSourceType.Slave.name());
            return;
         }
         DataSourceHolder.setType(DataSourceType.Master.name());
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   @Override
public int getOrder() {
      return 1;
   }
}

⑤:DataSourceHolder

package com.yzw.waldron.wenjing.db;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @Description:      設定、獲取資料來源連線
* @Auther:           Waldron Ye
* @CreateDate:       2018/7/8 9:39
* @Version:          1.0
*/
public class DataSourceHolder {
   private static Logger log = LoggerFactory.getLogger(DataSourceHolder.class);
   private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

   public static void setType(String jdbcType) {
      log.info("資料庫的型別是:" + jdbcType);
      contextHolder.set(jdbcType);
   }

   public static String getType() {
      return (String) contextHolder.get();
   }

   public static void clearType() {
      contextHolder.remove();
   }
}

⑥:DataSourceType

package com.yzw.waldron.wenjing.db;

public enum DataSourceType {

   // 主庫
Master("master"),
   // 從庫
Slave("slave");
   
   private DataSourceType(String name) {
      this.name = name;
   }

   private String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

⑦:DynamicDataSource

package com.yzw.waldron.wenjing.db;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import java.util.*;

/**
 * @Description: 描述
 * @Auther: Waldron Ye
 * @CreateDate: 2018/7/8 9:40
 * @Version: 1.0
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    private Object dataSourceMaster;

    private List<Object> dataSourceSlaves;

    private Random random = new Random();

    private List<String> dataSourceSlaveKeys = new ArrayList<String>();

    /*
     * (non-Javadoc) spring 從這裡獲取資料來源 key
     *
     * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()
     */
@Override
protected Object determineCurrentLookupKey() {
        if (DataSourceHolder.getType() == null || DataSourceHolder.getType().equals(DataSourceType.Master.name())) {
            return DataSourceType.Master.name();
        }
        // 從庫隨機選擇其中一個
String slaveStr = dataSourceSlaveKeys.get(random.nextInt(dataSourceSlaveKeys.size()));
        logger.info("slaveStr ->{}" + slaveStr);
        return slaveStr;
    }

    @Override
public void afterPropertiesSet() {
        if (this.dataSourceMaster == null) {
            throw new IllegalArgumentException("Property 'dataSourceMaster' is required");
        }
        // 設定預設資料來源
setDefaultTargetDataSource(dataSourceMaster);

        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.Master, dataSourceMaster);
        if (dataSourceSlaves != null) {
            for (int i = 0; i < dataSourceSlaves.size(); i++) {
                String slaveKey = DataSourceType.Slave.name() + i;
                dataSourceSlaveKeys.add(slaveKey);
                targetDataSources.put(slaveKey, dataSourceSlaves.get(i));
            }
        }
        // 設定全部資料來源
setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    public Object getDataSourceMaster() {
        return dataSourceMaster;
    }

    public void setDataSourceMaster(Object dataSourceMaster) {
        this.dataSourceMaster = dataSourceMaster;
    }

    public List<Object> getDataSourceSlaves() {
        return dataSourceSlaves;
    }

    public void setDataSourceSlaves(List<Object> dataSourceSlaves) {
        this.dataSourceSlaves = dataSourceSlaves;
    }

}

⑧:GlobalExceptionHandler

package com.yzw.waldron.wenjing.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 全域性異常處理
 * @Auther: Waldron Ye
 * @CreateDate: 2018/7/8 10:50
 * @Version: 1.0
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
public Object exceptionHandler(HttpServletRequest req, Exception e) {
        String requestURI = req.getRequestURI();
        String return_s = requestURI + " is error :" + e.getMessage();
        Map<String, Object> map = new HashMap<>();
        map.put("state", "0000");
        map.put("message", return_s);
        return map;
    }
}

⑨:IndexController

package com.yzw.waldron.wenjing.user.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class IndexController {

    @RequestMapping(value = "/check")
    @ResponseBody
public String check() {
//        int i = 1/0;
return "200";
    }
}

⑩:UserController

package com.yzw.waldron.wenjing.user.controller;

import com.yzw.waldron.wenjing.user.entity.User;
import com.yzw.waldron.wenjing.user.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequestMapping("user")
@RestController
public class UserController {
    private static Logger logger = LoggerFactory.getLogger(UserController.class);

    @Resource
private UserService userService;

    /**
     * 獲取使用者列表
     *
     * @return
*/
@RequestMapping(value = "/list")
    public Object list() {
        List<User> list = this.userService.getUserList();
        Map<String, Object> map = new HashMap<>();
        map.put("state", 100);
        map.put("message", "這是測試資訊");
        map.put("obj", list);
        logger.info("list -> {}", list);
        return map;
    }

    @RequestMapping(value = "/save")
    public Object save() {
        User user = new User();
        user.setName("test");
        user.setAddress("111111");
//        this.userService.saveUser(user);
this.userService.save();
        Map<String, Object> map = new HashMap<>();
        map.put("state", 100);
        map.put("message", "這是測試資訊");
        return map;
    }
}
package com.yzw.waldron.wenjing.user.controller;

import com.yzw.waldron.wenjing.user.entity.User;
import com.yzw.waldron.wenjing.user.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequestMapping("user")
@RestController
public class UserController {
    private static Logger logger = LoggerFactory.getLogger(UserController.class);

    @Resource
private UserService userService;

    /**
     * 獲取使用者列表
     *
     * @return
*/
@RequestMapping(value = "/list")
    public Object list() {
        List<User> list = this.userService.getUserList();
        Map<String, Object> map = new HashMap<>();
        map.put("state", 100);
        map.put("message", "這是測試資訊");
        map.put("obj", list);
        logger.info("list -> {}", list);
        return map;
    }

    @RequestMapping(value = "/save")
    public Object save() {
        User user = new User();
        user.setName("test");
        user.setAddress("111111");
//        this.userService.saveUser(user);
this.userService.save();
        Map<String, Object> map = new HashMap<>();
        map.put("state", 100);
        map.put("message", "這是測試資訊");
        return map;
    }
}

11、UserDao

package com.yzw.waldron.wenjing.user.dao;

import com.yzw.waldron.wenjing.user.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
@Mapper
public interface UserDao {

    /**
     *
     * 獲取使用者列表
     *
     * @return
*/
public List<User> getUserList();

    int saveUser(@Param("user") User user);

    int deleteUser();
}

12、User

package com.yzw.waldron.wenjing.user.entity;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    private Integer id;
    private String name;
    private Integer sex;
    private String address;
    private Integer age;
    private String remark;
    private Date createDate;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }
}

13、user.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 使用者授信流水對映 -->
<mapper namespace="com.yzw.waldron.wenjing.user.dao.UserDao">
    <!--獲取使用者列表-->
<select id="getUserList" resultType="com.yzw.waldron.wenjing.user.entity.User">
        SELECT t1.id,t1.`name`,t1.sex,t1.address,t1.age,t1.remark,t1.create_date AS createDate
        FROM `user` AS t1
        WHERE 1 = 1
    </select>

    <insert id="saveUser" parameterType="com.yzw.waldron.wenjing.user.entity.User">
        INSERT INTO user (
        address,
        age,
        create_date,
        name,
        remark
        ) VALUES (
       #{user.address},
       #{user.age},
       #{user.createDate},
       #{user.name},
       #{user.remark}
        )
    </insert>

    <delete id="deleteUser">
        DELETE FROM `user` WHERE id = '1'
    </delete>
</mapper>

14、UserServiceImpl

package com.yzw.waldron.wenjing.user.service.impl;

import com.yzw.waldron.wenjing.user.dao.UserDao;
import com.yzw.waldron.wenjing.user.entity.User;
import com.yzw.waldron.wenjing.user.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
private UserDao userDao;

    @Override
public List<User> getUserList() {
        return this.userDao.getUserList();
    }

    @Override
public int saveUser(User user) {
        return this.userDao.saveUser(user);
    }

    @Override
public int save() {
        User user = new User();
        user.setName("test");
        user.setAddress("111111");
        user.setAge(1);
        user.setCreateDate(new Date());
        user.setSex(2);
        int k = this.userDao.deleteUser();
        int j = this.userDao.saveUser(user);
        List list = getUserList();
        System.out.println("list:" + list);
        int i = 1/0;
        return 0;
    }

    @Override
public int deleteUser() {
        return this.userDao.deleteUser();
    }
}

15、UserService

package com.yzw.waldron.wenjing.user.service;

import com.yzw.waldron.wenjing.user.entity.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserService {


    public List<User> getUserList();


    int saveUser(@Param("user") User user);


    int save();

    int deleteUser();
}

16、WenjingApplication

package com.yzw.waldron.wenjing;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WenjingApplication {

   public static void main(String[] args) {
      SpringApplication.run(WenjingApplication.class, args);
   }
}

17、mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>


   <!-- mybatis對映檔案中所用到的別名配置 -->
<typeAliases>
      <package name="com.pro.ifun.usercenter.entity" />
   </typeAliases>

   <!-- 配置分頁外掛 -->
<plugins>
      <plugin interceptor="com.github.pagehelper.PageHelper">
         <!-- 設定資料庫型別 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六種資料庫-->
<property name="dialect" value="mysql"/>
      </plugin>
   </plugins>
</configuration>

18、spring-mybatis.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

   <!-- 抽象資料來源配置 可繼承 -->
<bean id="abstractDataSource" abstract="true" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
      <property name="driverClassName" value="${jdbc.wenjing.driverClassName}" />
      
      <!-- 獲取連線時最大等待時間,單位毫秒。配置了maxWait之後,預設啟用公平鎖,併