作者:付政委
烛火羸光映觥筹,踏入红尘何所求
微信公众号:bugstack虫洞栈 | 关注获取源码 沉淀、分享、成长,专注于原创专题案例,以最易学习编程的方式分享知识,让自己和他人都能有所收获。目前已完成的专题有;Netty4.x实战专题案例、用Java实现JVM、基于JavaAgent的全链路监控、手写RPC框架、架构设计专题案例[Ing]等。 你用剑?、我用刀?,好的代码都很烧?,望你不吝出招?!
在实际的业务开发中按照不同的场景需要,会有不同的业务架构也就同时会有不同的技术框架来支撑。那么这个专题想把一些常用的框架整理下,方便平时使用的同时也做一些技术沉淀。那么本章节会先搭建一个比较适合个人项目或者一些小公司开发项目的单体架构模型。服务功能展示页面如下;
微信公众号:bugstack虫洞栈 & 展示页面
整体的工程模型采用DDD四层架构,相对于MVC模式来讲。嗯!相当于家里三居换四居了!
1itstack-demo-frame-ssm
2└── src
3 ├── main
4 │ ├── java
5 │ │ └── org.itstack.demo
6 │ │ ├── application
7 │ │ │ └── UserService.java
8 │ │ ├── domain
9 │ │ │ ├── model
10 │ │ │ │ ├── aggregates
11 │ │ │ │ │ └── UserInfoCollect.java
12 │ │ │ │ ├── req
13 │ │ │ │ │ └── UserReq.java
14 │ │ │ │ └── vo
15 │ │ │ │ └── UserInfo.java
16 │ │ │ ├── repository
17 │ │ │ │ └── IUserRepository.java
18 │ │ │ └── service
19 │ │ │ └── UserServiceImpl.java
20 │ │ ├── infrastructure
21 │ │ │ ├── common
22 │ │ │ │ ├── EasyResult.java
23 │ │ │ │ └── PageRequest.java
24 │ │ │ ├── dao
25 │ │ │ │ └── IUserDao.java
26 │ │ │ ├── po
27 │ │ │ │ └── User.java
28 │ │ │ └── repository
29 │ │ │ └── UserRepository.java
30 │ │ └── interfaces
31 │ │ └── UserController.java
32 │ ├── resources
33 │ │ ├── mapper
34 │ │ ├── props
35 │ │ ├── spring
36 │ │ ├── logback.xml
37 │ │ ├── mybatis-config.xml
38 │ │ └── spring-config.xml
39 │ └── webapp
40 │ ├── page
41 │ ├── res
42 │ ├── WEB-INF
43 │ ├── index.html
44 │ └── res_layui.html
45 └── test
46 └── java
47 └── org.itstack.demo.test
48 └── ApiTest.java
以下对工程模块进行介绍,整体源码获取,可以关注公众号:bugstack虫洞栈,回复:框架搭建
应用层是比较薄的一层,不做具体逻辑开发。本工程里只包括服务的定义,具体逻辑有领域层实现。如果需要扩展可以做一些应用服务编排。
application/UserService.java & 定义接口
1/**
2 * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例
3 * 论坛:http://bugstack.cn
4 * Create by 付政委 on @2019
5 */
6public interface UserService {
7
8 UserInfoCollect queryUserInfoList(UserReq req);
9
10}
领域层是整个工程的核心服务层,这里负责处理具体的核心功能,完成领域服务。domain下可以有多个领域,每个领域里包括;聚合、请求对象、业务对象、仓储、服务。
domain/model/aggregates/UserInfoCollect.java & 定义聚合查询结果
1/**
2 * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例
3 * 论坛:http://bugstack.cn
4 * Create by 付政委 on @2019
5 */
6public class UserInfoCollect {
7
8 private Long count;
9 private List<UserInfo> userInfoList;
10
11 public UserInfoCollect() {
12 }
13
14 public UserInfoCollect(Long count, List<UserInfo> userInfoList) {
15 this.count = count;
16 this.userInfoList = userInfoList;
17 }
18
19 public Long getCount() {
20 return count;
21 }
22
23 public void setCount(Long count) {
24 this.count = count;
25 }
26
27 public List<UserInfo> getUserInfoList() {
28 return userInfoList;
29 }
30
31 public void setUserInfoList(List<UserInfo> userInfoList) {
32 this.userInfoList = userInfoList;
33 }
34}
domain/repository/IUserRepository.java & 定义仓储服务
1/**
2 * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例
3 * 论坛:http://bugstack.cn
4 * Create by 付政委 on @2019
5 */
6public interface IUserRepository {
7
8 UserInfoCollect queryUserInfoList(UserReq req);
9
10}
domain/service/UserServiceImpl.java & 对业务层功能进行实现
1/**
2 * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例
3 * 论坛:http://bugstack.cn
4 * Create by 付政委 on @2019
5 */
6@Service("userService")
7public class UserServiceImpl implements UserService {
8
9 @Resource(name = "userRepository")
10 private IUserRepository userRepository;
11
12 @Override
13 public UserInfoCollect queryUserInfoList(UserReq req) {
14 return userRepository.queryUserInfoList(req);
15 }
16
17}
infrastructure/dao/IUserDao.java & 数据库操作
1/**
2 * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例
3 * 论坛:http://bugstack.cn
4 * Create by 付政委 on @2019
5 */
6public interface IUserDao {
7
8 List<User> queryUserInfoList(UserReq req);
9
10 Long queryUserInfoCount(UserReq req);
11
12}
infrastructure/repository/UserRepository.java & 仓储功能实现如果有redis可以进行包装使用
1/**
2 * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例
3 * 论坛:http://bugstack.cn
4 * Create by 付政委 on @2019
5 */
6@Repository("userRepository")
7public class UserRepository implements IUserRepository {
8
9 @Resource
10 private IUserDao userDao;
11
12 @Override
13 public UserInfoCollect queryUserInfoList(UserReq req) {
14 Long count = userDao.queryUserInfoCount(req);
15 List<User> userList = userDao.queryUserInfoList(req);
16 List<UserInfo> userInfoList = new ArrayList<>();
17 userList.forEach(user -> {
18 UserInfo userInfo = new UserInfo();
19 userInfo.setUserId(user.getId());
20 userInfo.setName(user.getName());
21 userInfo.setAge(user.getAge());
22 userInfo.setAddress(user.getAddress());
23 userInfo.setEntryTime(user.getEntryTime());
24 userInfo.setStatus(user.getStatus());
25 userInfoList.add(userInfo);
26 });
27 return new UserInfoCollect(count, userInfoList);
28 }
29
30}
interfaces/UserController.java & 提供接口服务
1@Controller
2@RequestMapping("/api/user/")
3public class UserController {
4
5 private Logger logger = LoggerFactory.getLogger(UserController.class);
6
7 @Resource
8 private UserService userService;
9
10 @RequestMapping(path = "queryUserInfoList", method = RequestMethod.GET)
11 @ResponseBody
12 public EasyResult queryUserInfoList(String json, String page, String limit) {
13 try {
14 logger.info("查询用户信息列表开始。json:{}", json);
15 UserReq req = JSON.parseObject(json, UserReq.class);
16 if (null == req) req = new UserReq();
17 req.setPage(page, limit);
18 UserInfoCollect userInfoCollect = userService.queryUserInfoList(req);
19 logger.info("查询用户信息列表完成。userInfoCollect:{}", JSON.toJSONString(userInfoCollect));
20 return EasyResult.buildEasyResultSuccess(userInfoCollect.getCount(), userInfoCollect.getUserInfoList());
21 } catch (Exception e) {
22 logger.error("查询用户信息列表失败。json:{}", json, e);
23 return EasyResult.buildEasyResultError(e);
24 }
25 }
26
27}
这里包括了Spring、SpringMvc、mybatis、以及日志信息的配置;
mapper/User_Mapper.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper
3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5
6<mapper namespace="org.itstack.demo.infrastructure.dao.IUserDao">
7
8 <select id="queryUserInfoCount" resultType="java.lang.Long">
9 select count(id)
10 from user
11 <where>
12 <if test="name != null">
13 and name = #{name}
14 </if>
15 <if test="status != null">
16 and status = #{status}
17 </if>
18 </where>
19 </select>
20
21 <select id="queryUserInfoList" resultType="org.itstack.demo.infrastructure.po.User">
22 SELECT id, name, age, address, entryTime, status, remark, createTime, updateTime
23 FROM user
24 <where>
25 <if test="name != null">
26 and name = #{name}
27 </if>
28 <if test="status != null">
29 and status = #{status}
30 </if>
31 </where>
32 limit #{pageStart},#{pageEnd}
33 </select>
34
35</mapper>
props/jdbc.properties & 数据库链接信息
1db.jdbc.driverClassName=com.mysql.jdbc.Driver
2db.jdbc.url=jdbc:mysql://127.0.0.1:3306/itstack?createDatabaseIfNotExist=true&characterEncoding=utf-8&useUnicode=true
3db.jdbc.username=root
4db.jdbc.password=123456
spring/spring-config-datasource.xml & dbcp2数据源配置以及扫描Mapper等
1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans.xsd">
6
7 <!-- 1.数据库连接池 -->
8 <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
9 <property name="driverClassName" value="${db.jdbc.driverClassName}" />
10 <property name="url" value="${db.jdbc.url}" />
11 <property name="username" value="${db.jdbc.username}" />
12 <property name="password" value="${db.jdbc.password}" />
13 <property name="maxTotal" value="20" />
14 <property name="maxIdle" value="3" />
15 <property name="maxWaitMillis" value="15000" />
16 <property name="timeBetweenEvictionRunsMillis" value="60000" />
17 <property name="minEvictableIdleTimeMillis" value="180000" />
18 </bean>
19
20 <!-- 2.配置SqlSessionFactory对象 -->
21 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
22 <!-- 注入数据库连接池 -->
23 <property name="dataSource" ref="dataSource" />
24 <!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
25 <property name="configLocation" value="classpath:mybatis-config.xml" />
26 <!-- 扫描entity包 使用别名 -->
27 <property name="typeAliasesPackage" value="com.soecode.lyf.entity" />
28 <!-- 扫描sql配置文件:mapper需要的xml文件 -->
29 <property name="mapperLocations" value="classpath:mapper/*.xml" />
30 </bean>
31
32 <!-- 3.配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 -->
33 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
34 <!-- 注入sqlSessionFactory -->
35 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
36 <!-- 给出需要扫描Dao接口包 -->
37 <property name="basePackage" value="org.itstack.demo.infrastructure.dao" />
38 </bean>
39
40</beans>
resources/mybatis-config.xml
1<?xml version="1.0" encoding="UTF-8" ?>
2<!DOCTYPE configuration
3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
5<configuration>
6 <!-- 配置全局属性 -->
7 <settings>
8 <!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
9 <setting name="useGeneratedKeys" value="true" />
10 <!-- 使用列别名替换列名 默认:true -->
11 <setting name="useColumnLabel" value="true" />
12 <!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
13 <setting name="mapUnderscoreToCamelCase" value="true" />
14 </settings>
15</configuration>
resources/spring-config.xml
1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:context="http://www.springframework.org/schema/context"
5 xmlns:aop="http://www.springframework.org/schema/aop"
6 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
7 default-autowire="byName">
8
9 <context:component-scan base-package="org.itstack"/>
10 <aop:aspectj-autoproxy/>
11
12 <!-- 属性文件读入 -->
13 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
14 <property name="locations">
15 <list>
16 <value>classpath:props/*.properties</value>
17 </list>
18 </property>
19 </bean>
20
21 <import resource="classpath:spring/spring-*.xml"/>
22
23</beans>
24
1DROP TABLE user;
2CREATE TABLE user ( id bigint(11) NOT NULL AUTO_INCREMENT, name varchar(32), age int(4), address varchar(128), entryTime datetime, remark varchar(64), createTime datetime, updateTime datetime, status int(4) DEFAULT '0', PRIMARY KEY (id), INDEX idx_name (name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3insert into user (id, name, age, address, entryTime, remark, createTime, updateTime, status) values (1, '水水', 18, '吉林省榆树市黑林镇尹家村5组', '2019-12-22 00:00:00', '无', '2019-12-22 00:00:00', '2019-12-22 00:00:00', 0);
4insert into user (id, name, age, address, entryTime, remark, createTime, updateTime, status) values (2, '豆豆', 18, '辽宁省大连市清河湾司马道407路', '2019-12-22 00:00:00', '无', '2019-12-22 00:00:00', '2019-12-22 00:00:00', 1);
5insert into user (id, name, age, address, entryTime, remark, createTime, updateTime, status) values (3, '花花', 19, '辽宁省大连市清河湾司马道407路', '2019-12-22 00:00:00', '无', '2019-12-22 00:00:00', '2019-12-22 00:00:00', 0);