SSM整合(2): spring 与 mybatis 整合

在进行完spring与springmvc整合之后, 继续 spring与mybatis的整合.

既然是操作数据库, 那必然不能缺少了连接属性

一. db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

二. application.xml

将前一篇注释的部分, 再注释回来就行了, 是一个import操作

三. spring和mybatis的整合xml文件: 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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx" 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.1.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 自动搜索bean -->
    <!-- <context:annotation-config/>-->

    <!-- 自动扫描 -->
    <!--<context:component-scan base-package="org.elvin.ssm" />-->

    <!-- 引入配置文件 -->
    <context:property-placeholder location="classpath:conf/db.properties" />

    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <!--driverClassName会自动识别, 可以不配置-->
        <property name="driverClassName" value="${jdbc.driver}" />

        <!-- 配置初始化大小、最小、最大 -->
        <!--
            initialSize:初始化时建立物理连接的个数, 默认为0
            minIdle:最小连接池数量
            maxActive:最大连接池数量, 默认为8
        -->
        <property name="initialSize" value="1" />
        <property name="minIdle" value="1" />
        <property name="maxActive" value="20" />

        <!--获取连接时最大等待时间,单位ms-->
        <property name="maxWait" value="60000" />

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />

        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <!--
            validationQuery:用来检测连接是否有效的sql
            testWhileIdle:建议配置为true,默认false, 不影响性能,并且保证安全性,申请连接的时候检测,如果空闲时间大于
                          timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。
            testOnBorrow:申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。默认true
            testOnReturn:归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
        -->
        <property name="validationQuery" value="SELECT 1 " />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />

        <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
        <!--<property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />-->

        <!-- 监控统计用的filter:stat
        日志用的filter:log4j
        防御sql注入的filter:wall -->
        <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
        <property name="filters" value="stat" />
    </bean>

    <!-- mybatis 的工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:conf/mybatis.xml"/>
        <!-- 自动扫描mapping.xml文件 -->
        <property name="mapperLocations" value="classpath:mapper/**/*.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="org.elvin.ssm.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 注解方式配置事物 -->
    <!-- <tx:annotation-driven transaction-manager="transactionManager" /> -->

    <!-- 拦截器方式配置事物 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" isolation="REPEATABLE_READ" read-only="true" />
            <tx:method name="find*" isolation="REPEATABLE_READ" read-only="true" />
            <tx:method name="search*" isolation="REPEATABLE_READ" read-only="true" />
            <tx:method name="load*" isolation="REPEATABLE_READ" read-only="true" />

            <tx:method name="*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut id="pointCut" expression="execution(* org.elvin.ssm.service..*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut" />
    </aop:config>
</beans>

四. mybatis本身也可以有一个对自己的配置文件. mybatis.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>
    <typeAliases>
        <package name="org.elvin.ssm.pojo" />
    </typeAliases>
</configuration>

如果没有什么特别的配置, 这里也可以不写, 这个文件也可以不要, 但是要在spring-mybatis.xml文件中删除  configLocation 的配置

五. 加入日志文件 log4j.properties

log4j.rootLogger=DEBUG,Console,FILE  
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.layout=org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n  
#File Appender
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.FILE.File=C:/soft/logs/SSM.log  
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout  
log4j.appender.FILE.layout.ConversionPattern=[%d{HH:mm:ss,SSS}] [%l] [%t] [%-5p] : %m%n  

log4j.logger.java.sql.ResultSet=INFO  
log4j.logger.org.apache=INFO  
log4j.logger.java.sql.Connection=INFO  
log4j.logger.java.sql.Statement=INFO  
log4j.logger.java.sql.PreparedStatement=INFO

然后需要在web.xml文件中加入配置

    <!-- 加载log4j的配置文件log4j.properties -->
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>
            classpath:conf/log4j.properties
        </param-value>
    </context-param>
    <!-- 设定刷新日志配置文件的时间间隔,这里设置为10s -->
    <context-param>
        <param-name>log4jRefreshInterval</param-name>
        <param-value>10000</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

六. 后台代码

在mapper文件夹下, 加入一个mapper文件. BookMapper.java

package org.elvin.ssm.mapper;

import org.elvin.ssm.pojo.Book;

import java.util.List;

/**
 * author: Elvin
 * datetime: 2017/12/2 8:21
 * description:
 */
public interface BookMapper {

    /**
     * 根据id查询实体数据
     * @param id
     * @return
     */
    public Book find(Integer id);

    /**
     * 获取数据库中所有的数据
     * @return
     */
    public List<Book> getAll();

    /**
     * 新增
     * @param book
     * @return
     */
    public Integer insert(Book book);

    /**
     * 修改
     * @param book
     */
    public void update(Book book);

    /**
     * 删除
     * @param id
     */
    public void remove(Integer id);
}

这个文件是一个接口文件, 这里不需要我们手动去实现这个接口, 只需要在resources/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.elvin.ssm.mapper.BookMapper">

    <select id="find" parameterType="java.lang.Integer" resultType="org.elvin.ssm.pojo.Book">
      select * from book where id=#{id}
    </select>

    <select id="getAll" resultType="org.elvin.ssm.pojo.Book">
        select * from book
    </select>

    <insert id="insert" parameterType="org.elvin.ssm.pojo.Book" >
        insert into book(name, price, publishTime) values(#{name}, #{price}, #{publishTime})
    </insert>

    <update id="update" parameterType="org.elvin.ssm.pojo.Book">
        update book set name=#{name}, price=#{price}, publishTime=#{publishTime} where id=#{id]}
    </update>

    <delete id="remove" parameterType="java.lang.Integer">
        delete from book where id=#{id}
    </delete>

</mapper>

这样, dao中的部分, 就完成了. 接下来, 完成service中的部分

package org.elvin.ssm.service;

import org.elvin.ssm.pojo.Book;

import java.util.List;

public interface BookService {
    /**
     * 根据id查询实体数据
     * @param id
     * @return
     */
    public Book find(Integer id);

    /**
     * 获取数据库中所有的数据
     * @return
     */
    public List<Book> getAll();

    /**
     * 新增
     * @param book
     * @return
     */
    public Integer insert(Book book);

    /**
     * 修改
     * @param book
     */
    public void update(Book book);

    /**
     * 删除
     * @param id
     */
    public void remove(Integer id);
}

其实现类:

package org.elvin.ssm.serviceimpl;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.fastjson.JSON;
import org.elvin.ssm.mapper.BookMapper;
import org.elvin.ssm.pojo.Book;
import org.elvin.ssm.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * author: Elvin
 * datetime: 2017/12/2 8:26
 * description:
 */
@Service("bookService")
public class BookServiceImpl implements BookService {

    Log logger = LogFactory.getLog(BookServiceImpl.class);

    @Autowired
    private BookMapper bookMapper;

    /**
     * 根据id查询实体数据
     * @param id
     * @return
     */
    public Book find(Integer id){
        logger.info("find book : " + id);
        return bookMapper.find(id);
    }

    /**
     * 获取数据库中所有的数据
     * @return
     */
    public List<Book> getAll(){
        logger.info("getAll book");
        return bookMapper.getAll();
    }

    /**
     * 新增
     * @param book
     * @return
     */
    public Integer insert(Book book){
        logger.info("insert book : " + JSON.toJSONString(book));
        return bookMapper.insert(book);
    }

    /**
     * 修改
     * @param book
     */
    public void update(Book book){
        logger.info("update book : " + JSON.toJSONString(book));
        bookMapper.update(book);
    }

    /**
     * 删除
     * @param id
     */
    public void remove(Integer id){
        logger.info("remove book : " + id);
        bookMapper.remove(id);
    }
}

controller中, 新建一个控制器, 来验证一下程序是否能正常运行

package org.elvin.ssm.controller;

import org.elvin.ssm.pojo.Book;
import org.elvin.ssm.pojo.ResModel;
import org.elvin.ssm.service.BookService;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * author: Elvin
 * datetime: 2017/11/29 20:06
 * description:
 */
@Controller
@RequestMapping("hello")
public class HelloController {

    @Autowired
    private BookService bookService;

    @RequestMapping("index")
    public String index(ModelMap model){

        List<Book> bookList = bookService.getAll();

        model.put("bookList", bookList);

        return "index";
    }

    @RequestMapping(value = "book/{id}", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public Book book(@PathVariable("id") Integer id){
       Book b = bookService.find(id);
       return b;
    }

    @RequestMapping(value = "get", method = RequestMethod.POST)
    public @ResponseBody Map<String, Object> getData(@RequestParam("id") Integer id){
        Map<String, Object> map = new HashMap<>();
        map.put("name", "hahhha");
        map.put("age", 20);
        return map;
    }

    @GetMapping("addData")
    @ResponseBody
    public ResModel addData(){
        ResModel resObj = new ResModel("新增数据失败", 0, null);
        try{
            List<Book> list = getBookList();
            list.forEach(n->{
                bookService.insert(n);
            });
            resObj.setMsg("新增成功");
            resObj.setCode(1);
        }
        catch (Exception e){
            System.out.println(e.getMessage());

        }
        return resObj;
    }

    //region private method
    private List<Book> getBookList(){
        List<Book> bookList = new ArrayList<>();
        String[] nameStrs = {"吴", "一", "雪", "动", "额", "阿", "前", "里", "排"};
        Random r = new Random();
        String timeStr = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < 10 ; i++){
            Book b = new Book();
            b.setId(i+1);
            b.setName(nameStrs[r.nextInt(5)] + nameStrs[r.nextInt(9)]);
            b.setPublishTime(timeStr);
            b.setPrice(r.nextInt(100));
            bookList.add(b);
        }
        return bookList;
    }
    //endregion
}

这里我做了一个Json数据返回的规范实体

package org.elvin.ssm.pojo;

/**
 * author: Elvin
 * datetime: 2017/12/2 13:19
 * description:
 */
public class ResModel {
    private String msg;

    private Integer code;

    private Object resObj;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public Object getResObj() {
        return resObj;
    }

    public void setResObj(Object resObj) {
        this.resObj = resObj;
    }

    public ResModel(String msg, Integer code, Object resObj) {
        this.msg = msg;
        this.code = code;
        this.resObj = resObj;
    }
}

七. 验证

1. 加数据到数据库中

这里的价格和时间, 我在数据库中用的是 int 和 varchar 类型的.  在实际使用中, 价格不要使用decimal去存储, 看需求, 如果money不是很大, 可以用int, 如果大, 则使用long来存储. 这样能保证数据的精确性. 而对于时间类型, 使用字符串类型去处理, 其实完全是可以的, 并且在实际使用中, 我觉得更方便. 

有了数据之后, 可以来查询一下

 

原文地址:https://www.cnblogs.com/elvinle/p/7954069.html