springboot 2.0.3.RELEASE + druid 1.1.10 多資料來源(可用讀寫分離) + mysql + ssm搭建
阿新 • • 發佈:2019-02-07
開始,先上一張專案總體圖片:
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 newDataSourceAspect(); } }
②: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; importorg.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之後,預設啟用公平鎖,併