有點乾貨 | 應用服務之SSM整合:Spring4 + SpringMvc + Mybatis

微信公衆號:bugstack蟲洞棧 | 關注獲取源碼 沉澱、分享、成長,專一於原創專題案例,以最易學習編程的方式分享知識,讓本身和他人都能有所收穫。目前已完成的專題有;Netty4.x實戰專題案例、用Java實現JVM、基於JavaAgent的全鏈路監控、手寫RPC框架、架構設計專題案例[Ing]等。 你用劍🗡、我用刀🔪,好的代碼都很燒😏,望你不吝出招💨!html

前言介紹

在實際的業務開發中按照不一樣的場景須要,會有不一樣的業務架構也就同時會有不一樣的技術框架來支撐。那麼這個專題想把一些經常使用的框架整理下,方便平時使用的同時也作一些技術沉澱。那麼本章節會先搭建一個比較適合我的項目或者一些小公司開發項目的單體架構模型。服務功能展現頁面以下;java

微信公衆號:bugstack蟲洞棧 & 展現頁面

工程環境

  1. JDK1.8
  2. Maven 3.2.3
  3. Spring 4.3.24.RELEASE + SpringMvc + Mybatis 3.3.0
  4. Mysql 5.6 + dbcp2
  5. layui 2.5.4

工程模型

總體的工程模型採用DDD四層架構,相對於MVC模式來說。嗯!至關於家裏三居換四居了!mysql

itstack-demo-frame-ssm
└── src
    ├── main
    │   ├── java
    │   │   └── org.itstack.demo
    │   │       ├── application	
    │   │       │	└── UserService.java	
    │   │       ├── domain
    │   │       │	├── model
    │   │       │	│   ├── aggregates
    │   │       │	│   │   └── UserInfoCollect.java
    │   │       │	│   ├── req
    │   │       │	│   │   └── UserReq.java		
    │   │       │	│   └── vo
    │   │       │	│       └── UserInfo.java	
    │   │       │	├── repository
    │   │       │	│   └── IUserRepository.java	
    │   │       │	└── service	
    │   │       │	    └── UserServiceImpl.java	
    │   │       ├── infrastructure
    │   │       │	├── common
    │   │       │	│   ├── EasyResult.java
    │   │       │	│   └── PageRequest.java
    │   │       │	├── dao
    │   │       │	│   └── IUserDao.java	
    │   │       │	├── po
    │   │       │	│   └── User.java		
    │   │       │	└── repository
    │   │       │	    └── UserRepository.java	
    │   │       └── interfaces
    │   │        	└── UserController.java
    │   ├── resources	
    │   │   ├── mapper
    │   │   ├── props	
    │   │   ├── spring
    │   │   ├── logback.xml
    │   │   ├── mybatis-config.xml
    │   │   └── spring-config.xml
    │   └── webapp
    │       ├── page
    │       ├── res
    │       ├── WEB-INF
    │       ├── index.html
    │       └── res_layui.html
    └── test
         └── java
             └── org.itstack.demo.test
                 └── ApiTest.java
複製代碼

如下對工程模塊進行介紹,總體源碼獲取,能夠關注公衆號:bugstack蟲洞棧,回覆:框架搭建web

application應用層

應用層是比較薄的一層,不作具體邏輯開發。本工程裏只包括服務的定義,具體邏輯有領域層實現。若是須要擴展能夠作一些應用服務編排。redis

application/UserService.java & 定義接口spring

/** * 微信公衆號:bugstack蟲洞棧 | 歡迎關注學習專題案例 * 論壇:http://bugstack.cn * Create by 付政委 on @2019 */
public interface UserService {

    UserInfoCollect queryUserInfoList(UserReq req);

}
複製代碼

domain領域層

領域層是整個工程的核心服務層,這裏負責處理具體的核心功能,完成領域服務。domain下能夠有多個領域,每一個領域裏包括;聚合、請求對象、業務對象、倉儲、服務。sql

domain/model/aggregates/UserInfoCollect.java & 定義聚合查詢結果數據庫

/** * 微信公衆號:bugstack蟲洞棧 | 歡迎關注學習專題案例 * 論壇:http://bugstack.cn * Create by 付政委 on @2019 */
public class UserInfoCollect {

    private Long count;
    private List<UserInfo> userInfoList;

    public UserInfoCollect() {
    }

    public UserInfoCollect(Long count, List<UserInfo> userInfoList) {
        this.count = count;
        this.userInfoList = userInfoList;
    }

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }

    public List<UserInfo> getUserInfoList() {
        return userInfoList;
    }

    public void setUserInfoList(List<UserInfo> userInfoList) {
        this.userInfoList = userInfoList;
    }
}
複製代碼

domain/repository/IUserRepository.java & 定義倉儲服務apache

/** * 微信公衆號:bugstack蟲洞棧 | 歡迎關注學習專題案例 * 論壇:http://bugstack.cn * Create by 付政委 on @2019 */
public interface IUserRepository {

    UserInfoCollect queryUserInfoList(UserReq req);

}

複製代碼

domain/service/UserServiceImpl.java & 對業務層功能進行實現編程

/** * 微信公衆號:bugstack蟲洞棧 | 歡迎關注學習專題案例 * 論壇:http://bugstack.cn * Create by 付政委 on @2019 */
@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource(name = "userRepository")
    private IUserRepository userRepository;

    @Override
    public UserInfoCollect queryUserInfoList(UserReq req) {
        return userRepository.queryUserInfoList(req);
    }

}
複製代碼

infrastructure基礎層

  1. 實現領域層倉儲定義
  2. 數據庫操做爲非業務屬性的功能操做
  3. 在倉儲實現層進行組合裝配DAO&Redis&Cache等

infrastructure/dao/IUserDao.java & 數據庫操做

/** * 微信公衆號:bugstack蟲洞棧 | 歡迎關注學習專題案例 * 論壇:http://bugstack.cn * Create by 付政委 on @2019 */
public interface IUserDao {

    List<User> queryUserInfoList(UserReq req);

    Long queryUserInfoCount(UserReq req);

}

複製代碼

infrastructure/repository/UserRepository.java & 倉儲功能實現若是有redis能夠進行包裝使用

/** * 微信公衆號:bugstack蟲洞棧 | 歡迎關注學習專題案例 * 論壇:http://bugstack.cn * Create by 付政委 on @2019 */
@Repository("userRepository")
public class UserRepository implements IUserRepository {

    @Resource
    private IUserDao userDao;

    @Override
    public UserInfoCollect queryUserInfoList(UserReq req) {
        Long count = userDao.queryUserInfoCount(req);
        List<User> userList = userDao.queryUserInfoList(req);
        List<UserInfo> userInfoList = new ArrayList<>();
        userList.forEach(user -> {
            UserInfo userInfo = new UserInfo();
            userInfo.setUserId(user.getId());
            userInfo.setName(user.getName());
            userInfo.setAge(user.getAge());
            userInfo.setAddress(user.getAddress());
            userInfo.setEntryTime(user.getEntryTime());
            userInfo.setStatus(user.getStatus());
            userInfoList.add(userInfo);
        });
        return new UserInfoCollect(count, userInfoList);
    }

}
複製代碼

interfaces接口層

  1. 包裝應用接口對外提供api,目前這一層比較簡單隻須要進行接口使用便可
  2. 若是是對外部提供服務接口,那麼可使用DTO方式進行轉換,避免污染到業務類

interfaces/UserController.java & 提供接口服務

@Controller
@RequestMapping("/api/user/")
public class UserController {

    private Logger logger = LoggerFactory.getLogger(UserController.class);

    @Resource
    private UserService userService;

    @RequestMapping(path = "queryUserInfoList", method = RequestMethod.GET)
    @ResponseBody
    public EasyResult queryUserInfoList(String json, String page, String limit) {
        try {
            logger.info("查詢用戶信息列表開始。json:{}", json);
            UserReq req = JSON.parseObject(json, UserReq.class);
            if (null == req) req = new UserReq();
            req.setPage(page, limit);
            UserInfoCollect userInfoCollect = userService.queryUserInfoList(req);
            logger.info("查詢用戶信息列表完成。userInfoCollect:{}", JSON.toJSONString(userInfoCollect));
            return EasyResult.buildEasyResultSuccess(userInfoCollect.getCount(), userInfoCollect.getUserInfoList());
        } catch (Exception e) {
            logger.error("查詢用戶信息列表失敗。json:{}", json, e);
            return EasyResult.buildEasyResultError(e);
        }
    }

}
複製代碼

resource配置

這裏包括了Spring、SpringMvc、mybatis、以及日誌信息的配置;

mapper/User_Mapper.xml

<?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="org.itstack.demo.infrastructure.dao.IUserDao">

    <select id="queryUserInfoCount" resultType="java.lang.Long">
        select count(id)
        from user
        <where>
            <if test="name != null">
                and name = #{name}
            </if>
            <if test="status != null">
                and status = #{status}
            </if>
        </where>
    </select>

    <select id="queryUserInfoList" resultType="org.itstack.demo.infrastructure.po.User">
      SELECT id, name, age, address, entryTime, status, remark, createTime, updateTime
      FROM user
      <where>
          <if test="name != null">
              and name = #{name}
          </if>
          <if test="status != null">
              and status = #{status}
          </if>
      </where>
      limit #{pageStart},#{pageEnd}
    </select>

</mapper>
複製代碼

props/jdbc.properties & 數據庫連接信息

db.jdbc.driverClassName=com.mysql.jdbc.Driver
db.jdbc.url=jdbc:mysql://127.0.0.1:3306/itstack?createDatabaseIfNotExist=true&amp;characterEncoding=utf-8&amp;useUnicode=true
db.jdbc.username=root
db.jdbc.password=123456
複製代碼

spring/spring-config-datasource.xml & dbcp2數據源配置以及掃描Mapper等

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

    <!-- 1.數據庫鏈接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="${db.jdbc.driverClassName}" />
        <property name="url" value="${db.jdbc.url}" />
        <property name="username" value="${db.jdbc.username}" />
        <property name="password" value="${db.jdbc.password}" />
        <property name="maxTotal" value="20" />
        <property name="maxIdle" value="3" />
        <property name="maxWaitMillis" value="15000" />
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <property name="minEvictableIdleTimeMillis" value="180000" />
    </bean>

    <!-- 2.配置SqlSessionFactory對象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入數據庫鏈接池 -->
        <property name="dataSource" ref="dataSource" />
        <!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
        <property name="configLocation" value="classpath:mybatis-config.xml" />
        <!-- 掃描entity包 使用別名 -->
        <property name="typeAliasesPackage" value="com.soecode.lyf.entity" />
        <!-- 掃描sql配置文件:mapper須要的xml文件 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml" />
    </bean>

    <!-- 3.配置掃描Dao接口包,動態實現Dao接口,注入到spring容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 注入sqlSessionFactory -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <!-- 給出須要掃描Dao接口包 -->
        <property name="basePackage" value="org.itstack.demo.infrastructure.dao" />
    </bean>

</beans>
複製代碼

resources/mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 配置全局屬性 -->
	<settings>
		<!-- 使用jdbc的getGeneratedKeys獲取數據庫自增主鍵值 -->
		<setting name="useGeneratedKeys" value="true" />
		<!-- 使用列別名替換列名 默認:true -->
		<setting name="useColumnLabel" value="true" />
		<!-- 開啓駝峯命名轉換:Table{create_time} -> Entity{createTime} -->
		<setting name="mapUnderscoreToCamelCase" value="true" />
	</settings>
</configuration>
複製代碼

resources/spring-config.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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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"
       default-autowire="byName">

    <context:component-scan base-package="org.itstack"/>
    <aop:aspectj-autoproxy/>

    <!-- 屬性文件讀入 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:props/*.properties</value> </list> </property> </bean> <import resource="classpath:spring/spring-*.xml"/> </beans> 複製代碼

itstack.sql

DROP TABLE user;
CREATE 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;
insert 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);
insert 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);
insert 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);
複製代碼

綜上總結

  • 此工程模型基於SSM比較適合開發ERP服務,ERP使用layui頁面清新,功能完善
  • 工程框架採用了DDD架構模式,在此架構模式下能夠更容易的開發系統,適應後比MVC更加方便
  • 後續將繼續拓展架構服務搭建,包括一些Dubbo、Redis、mq等使用,方便本身也方便他人

微信公衆號:bugstack蟲洞棧,歡迎關注&獲取源碼
相關文章
相關標籤/搜索