SSM框架

SSM项目整合

一.环境准备

  • 开发工具:idea2020.1

  • 构建工具:maven3.8.4

  • spring框架5.2.18;JDK:1.8;数据库:MySQL;连接池:德鲁伊

二.环境搭建

2.1 基本环境搭建

2.1.1构建model

SSM框架

 

2.1.3创建基本目录

SSM框架

 

2.2 pom文件依赖包引入

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.2.18.RELEASE</spring.version>
  </properties>
​
  <dependencies>
    <!--测试依赖-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!--日志-->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>
    <!--解析JSON-->
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.7</version>
    </dependency>
    <!--servlet-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <!--作用范围是provided表示,打包的时候不会将jar包打入war包-->
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
       <!--上传文件依赖jar包-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>
    <!--Spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--spring AOP和aspectj框架整合的模块-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--事务需要的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!--链接数据库要用-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <!-- mysql jdbc驱动包 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.27</version>
    </dependency>
    <!--Druid数据库连接池 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.20</version>
    </dependency>
    <!-- mybatis框架包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.2</version>
    </dependency>
    <!-- mybatis和spring整合依赖包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.2</version>
    </dependency>
    <!--分页依赖-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.2.1</version>
    </dependency>
  </dependencies>
​
  <build>
    <!--资源插件,处理src/main/java目录的xml-->
    <resources>
      <resource>
        <directory>src/main/java</directory>    <!--所在的目录-->
        <includes><!--包括properties和xml都会被扫描-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>true</filtering>
      </resource>
      <resource>
        <directory>src/main/resources</directory>    <!--所在的目录-->
        <includes><!--包括properties和xml都会被扫描-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
      </resource>
    </resources>
  </build>

2.3 编写配置文件

2.3.1编写spring配置文件

  1. j将所有的配置文件都放在在src\main\resources目录下面,方便管理维护;

  2. 创建spring的xml配置文件applicationContext.xmlSSM框架

  3. 编写applicationContext.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:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                               http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd">
    ​
    <!--开启扫描-->
        <context:component-scan base-package="com.yang">
            <!--配置哪些注解不扫描 Controller用springMVC-->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
        </context:component-scan>
        <!--读取外部配置文件-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <!--将Druid数据源交给Spring IOC容器来管理-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="username" value="${prop.username}"/>
            <property name="password" value="${prop.password}"/>
            <property name="url" value="${prop.url}"/>
            <property name="driverClassName" value="${prop.driverClassName}"/>
            <property name="initialSize" value="${prop.initialSize}"/>
            <property name="maxActive" value="${prop.maxActive}"/>
        </bean>
        <!--SqlSessionFactory 会话工厂交给spring容器管理-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>          <!-- 加载数据环境   -->
            <!--  绑定mybatis配置文件     -->
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <!--   几乎所有的东西都能在这里面配,完全不需要mybatis的核心配置  根据个人喜好,个人感觉分开一点维护比较容易 -->
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.yang.mapper"></property>
        </bean>
        <!-- 事务管理器 -->
        <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <tx:annotation-driven transaction-manager="transactionManager"/>
    ​
    </beans>

2.3.2编写jdbc.properties文件

prop.username=用户名
prop.password=密码
prop.url=jdbc:mysql://localhost:3306/数据库名
#driverClassName
prop.driverClassName=com.mysql.cj.jdbc.Driver
#初始化连接数
prop.initialSize=10
#最小连接数
prop.minIdle=5
#最大连接数
prop.maxActive=20
#最大等待时间
prop.maxWait=5000

2.3.3配置springMVC文件

<?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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
​
    <!--开启注解扫描,只扫描Controller注解,直接指定到controller,否则会无法添加事务-->
    <context:component-scan base-package="com.yang.controller" />
    <!--配置的视图解析器对象;这里使用jsp;也可以使用其他的视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--也可以放开下面这一行; 就只能解析jsp了;-->
        <!--<property name="suffix" value=".jsp"/>-->
        <property name="contentType" >
            <value>text/html; charset=UTF-8</value>
        </property>
    </bean>
    <!--MVC注解驱动,如果不加这个驱动所有的都会交给默认的请求去处理了,只能访问静态资源,而其他跳      转功能等无法使用所以default-servlet-handler标签要和annotation-driven一起使用-->
    <mvc:annotation-driven/>
    <!--开启静态资源扫描,由于设置了DispatcherServlet所以所有的请求都会交给DispatcherServlet去处理,而当它处理不了的时候,就需要交给默认的servlet处理
    web阶段是由于Tomcat中设置为默认servlet,而mvc中设置为DispatcherServlet,起冲突时,就地原则,就使用DispatcherServlet,所以需要在开启该标签,当DispatcherServlet处理不了时,交给默认的去处理,若也处理不了就404了-->
    <mvc:default-servlet-handler/>
    <!--文件上传解析类 id必须是multipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
    <!--视图控制器,当视图只配置一个跳转页面的时候可以用 path路径,view-name映射路径-->
    <mvc:view-controller path="/in" view-name="index.jsp"/>
    <mvc:view-controller path="/" view-name="in.html"/>
</beans>

2.3.4编写mybatis配置文件

<?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>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--配置插件,分页查询-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>
    </plugins>
​
</configuration>

2.3.5配置web.xml文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
​
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!--加载applicationContext文件-->
    <!--  加载全局初始化参数,让服务器启动就加载spring配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  <!--配置spring监听器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--设置字符编码-->
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--设置请求编码utf-8编码-->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <!--设置响应编码为utf-8-->
    <init-param>
      <param-name>ForceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!--配置HiddenHttpMethodFilter以使用put和delete请求-->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!--配置springMVC前段控制器,对浏览器请求统一处理-->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--配置springMVC的配置文件的位置和名称-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:SpringMVC.xml</param-value>
    </init-param>
    <!--将初始化时间提前到服务器启动时间-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <!--/的意思就是接受除了.jsp以外的所有请求;/*表示所有包括.jsp-->
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
到这里基本的框架就搭好了,接下来就是业务代码的编写了

三.业务代码

3.1编写前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>你好</h1>
<a href="user/2">查询</a><br/>
<hr/>
<form action="user" method="post">
    用户名<input type="text" name="username" /><br/>
    密码<input type="text" name="password" /><br/>
    <input type="submit" value="添加用户" /><br/>
</form><hr/>
<form action="user/20" method="post">
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="删除用户" /><br/>
</form><hr/>
</body>
</html>

3.2后端代码

3.2.1基本结构

 SSM框架

 

  • 一般要将dao接口和mapper文件放在同一目录下才行;但为了方便管理将其放在resource目录下面

3.2.2 Controller

/**
 * (User)表控制层
 *
 * @author makejava
 * @since 2021-12-27 14:38:49
 */
@RestController
@RequestMapping("user")
public class UserController {
    /**
     * 服务对象
     */
    @Resource
    private UserService userService;
​
   /*
     * 分页查询
     * @return 查询结果
     */
    @GetMapping
    public List<User> queryByPage() {
        //使用分页查询插件,下面的参数分别是页数和每页展示数量
        PageHelper.startPage(2,2);
        return userService.queryByPage();
    }
​
    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("{id}")
    public ResponseEntity<User> queryById(@PathVariable("id") Integer id) {
        return ResponseEntity.ok(this.userService.queryById(id));
    }
​
    /**
     * 新增数据
     *
     * @param user 实体
     * @return 新增结果
     */
    @PostMapping
    public ResponseEntity<User> add(User user) {
        return ResponseEntity.ok(this.userService.insert(user));
    }
​
    /**
     * 编辑数据
     *
     * @param user 实体
     * @return 编辑结果
     */
    @PutMapping
    public ResponseEntity<User> edit(User user) {
        return ResponseEntity.ok(this.userService.update(user));
    }
​
    /**
     * 删除数据
     *
     * @param id 主键
     * @return 删除是否成功
     */
    @DeleteMapping
    public ResponseEntity<Boolean> deleteById(Integer id) {
        return ResponseEntity.ok(this.userService.deleteById(id));
    }
​
}

3.2.3 Service和serviceImpl

/**
 * (User)表服务接口
 *
 * @author makejava
 * @since 2021-12-27 14:39:23
 */
public interface UserService {

    /**
     * 分页查询
     * @return
     */
    List<User> queryByPage();

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

     /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    User insert(User user);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    User update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    boolean deleteById(Integer id);

}

serviceImpl

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2021-12-27 14:39:24
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    @Override
    public List<User> queryByPage() {
        return userDao.queryPage();
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Integer id) {
        return this.userDao.queryById(id);
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    @Transactional(rollbackFor=Exception.class)
    public User insert(User user) {
        userDao.insert(user);
        int i = 12/0;
        return user;
    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.userDao.deleteById(id) > 0;
    }
}

3.2.4 dao接口

/**
 * (User)表数据库访问层
 *
 * @author makejava
 * @since 2021-12-27 14:40:01
 */
public interface UserDao {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

    /**
     * 查询指定行数据
     *
     * @param user     查询条件
     * @param pageable 分页对象
     * @return 对象列表
     */
    List<User> queryAllByLimit(User user, @Param("pageable") Pageable pageable);

    /**
     * 统计总行数
     *
     * @param user 查询条件
     * @return 总行数
     */
    long count(User user);

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int insert(User user);

    /**
     * 批量新增数据(MyBatis原生foreach方法)
     *
     * @param entities List<User> 实例对象列表
     * @return 影响行数
     */
    int insertBatch(@Param("entities") List<User> entities);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 影响行数
     */
    int deleteById(Integer id);

    List<User> queryPage();
}

3.2.5 mapper文件

<?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.yang.mapper.UserDao">
​
    <resultMap type="com.yang.bean.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="username" column="username" jdbcType="VARCHAR"/>
        <result property="password" column="password" jdbcType="VARCHAR"/>
        <result property="email" column="email" jdbcType="VARCHAR"/>
    </resultMap>
​
    <!--分页查询 返回类型还可以是user,mybatis会自动把查到的对象封装到集合中-->
    <select id="queryPage" resultMap="UserMap">
        select
          id, username, password, email
        from user
    </select>
    <!--查询单个-->
    <select id="queryById" resultMap="UserMap">
        select
          id, username, password, email
        from user
        where id = #{id}
    </select>
​
    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="UserMap">
        select
        id, username, password, email
        from user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="username != null and username != ''">
                and username = #{username}
            </if>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </where>
        limit #{pageable.offset}, #{pageable.pageSize}
    </select>
​
    <!--统计总行数-->
    <select id="count" resultType="java.lang.Long">
        select count(1)
        from user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="username != null and username != ''">
                and username = #{username}
            </if>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </where>
    </select>
​
    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into user(username, password, email)
        values (#{username}, #{password}, #{email})
    </insert>
​
    <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
        insert into user(username, password, email)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.username}, #{entity.password}, #{entity.email})
        </foreach>
    </insert>
​
    <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
        insert into user(username, password, email)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.username}, #{entity.password}, #{entity.email})
        </foreach>
        on duplicate key update
        username = values(username),
        password = values(password),
        email = values(email)
    </insert>
​
    <!--通过主键修改数据-->
    <update id="update">
        update user
        <set>
            <if test="username != null and username != ''">
                username = #{username},
            </if>
            <if test="password != null and password != ''">
                password = #{password},
            </if>
            <if test="email != null and email != ''">
                email = #{email},
            </if>
        </set>
        where id = #{id}
    </update>
​
    <!--通过主键删除-->
    <delete id="deleteById">
        delete from user where id = #{id}
    </delete>
​
</mapper>

四 测试

  • 新建一个Tomcat服务,将包部署到Tomcat就可以测试啦

  • 页面不好看自己优化吧

五 一些问题

  1. pom文件中的依赖都要用到,少了会启动失败

  2. mybatis和spring可以全部整合到一起;但是不方便维护

  3. 在MVC的扫描中只能扫描controller;否则会导致配置事务不起作用

 <!--扫描Controller-->
    <context:component-scan base-package="com.yang">
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller" />
        <!--下面这个是防止事务没起作用,spring.xml的父容器先于Servlet的子容器生效,将Service提前加载了。这里不用再进行加载装配;或者像上面的配置一样,直接指定只扫controller-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
    </context:component-scan>

上一篇:NSPredicate匹配中文正


下一篇:idea 使用 Docker 打包镜像的两种方式_07