前一段时间开发java web项目都是采用的SSH框架,开发中发现在使用Hibernate做持久层开发的时候用法不够灵活,过于笨重,因此,改用MyBaties,结合Spring、SpringMvc框架,现将配置过程梳理如下:
一、项目结构
项目整体结构如上所示,
java文件夹下存放所有的class文件,包含mybaties的mapper 文件。
resource文件夹存放一些与配置相关的文件:
- 如spring的bean配置文件applicationContext.xml,
- 用于配置数据库连接的配置文件jdbc.properties,
- 用于日志打印的log4j配置文件log4j.properties,
- 用于存储一些系统配置的系统配置文件sysconfig.properties,
- mybaties的配置文件mybatiesConfig.xml。
二、详细配置
1、maven配置文件pom.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ssm</groupId>
<artifactId>com.ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring-version>4.2.3.release</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<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-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework</groupId>-->
<!--<artifactId>spring-oxm</artifactId>-->
<!--<version>${spring-version}</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework</groupId>-->
<!--<artifactId>spring-instrument</artifactId>-->
<!--<version>${spring-version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- Spring Mvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<!-- Spring orm-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- jdbc -->
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
<!-- sql server-->
<dependency>
<groupId>com.microsoft</groupId>
<artifactId>sqljdbc</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- Json parse-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.9</version>
</dependency>
<!--utils -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<!--map bean converter-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.7.0</version>
</dependency>
<!-- data page -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
<!--log -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
<!-- 特别注意,以下这部分配置不可缺少,如果不配置将会无法在打包时
将mybaties的mapper 文件打包进war包,导致报错!!!-->
<build>
<resources>
<!--编译之后包含xml-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>com/ssm/maps/**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
2、配置Spring核心配置文件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-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 1、引入数据库配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 2、配置数据库连接 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性,属性值从数据库连接配置文件中获取 -->
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.connectionURL}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30" />
<property name="minPoolSize" value="10" />
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false" />
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000" />
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2" />
</bean>
<!-- 3、配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<!-- 配置MyBaties全局配置文件:mybatisConfig.xml -->
<property name="configLocation" value="classpath:mybatisConfig.xml" />
<!-- 扫描entity包 使用别名 -->
<property name="typeAliasesPackage" value="com.ssm.bean"/>
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations" value="classpath:com/ssm/maps/**/*.xml" />
</bean>
<!-- 4、配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage" value="com.ssm.dao" />
</bean>
<!-- 5、开启service 注解扫描-->
<context:component-scan base-package="com.ssm.service" />
<!-- 6、配置事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 7、方法自动注入事务,原则为以特定单词开头的方法自动注入事务处理,无需手动提交事务 -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="get*">
readOnly,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="query*">
readOnly,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="find*">
readOnly,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="search*">
readOnly,ISOLATION_DEFAULT,-Exception
</prop>
<prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="remove*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="execute*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="do*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="set*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="edit*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="process">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="*">
PROPAGATION_SUPPORTS,ISOLATION_DEFAULT,-Exception
</prop>
</props>
</property>
</bean>
</beans>
3、数据库配置文件jdbc.properties
#Oracle database
#jdbc.driverClass=oracle.jdbc.driver.OracleDriver
#jdbc.connectionURL=jdbc:oracle:thin:@//localhost:1521/ssmbase
#jdbc.username=LOUIS
#jdbc.password=123456
#SqlServer database
#jdbc.driverClass=com.microsoft.sqlserver.jdbc.SQLServerDriver
#jdbc.connectionURL=jdbc:sqlserver://localhost:1433;DatabaseName=ssmbase
#jdbc.username=LOUIS
#jdbc.password=123456
#MySql database
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://localhost:3306/ssmbase?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
4、在配置applicationContext.xml文件时,引入了mybaties的全局配置文件,Mybaties全局配置文件如下:
<?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="cacheEnabled" value="true" />
<!-- 允许 JDBC 支持生成的键。需要适合的驱动。如果设置为 true 则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如 Derby) -->
<setting name="useGeneratedKeys" value="true" />
<!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 -->
<setting name="defaultExecutorType" value="REUSE" />
<setting name="jdbcTypeForNull" value="NULL" />
<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间。 -->
<setting name="defaultStatementTimeout" value="25000" />
<!-- 配置打印出日志的,感觉没什么用 -->
<setting name="logImpl" value="LOG4J" />
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
<setting name="callSettersOnNulls" value="true"/>
</settings>
</configuration>
5、配置好maven库、spring核心文件,接下来配置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" xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解模式 -->
<!-- 简化配置:
(1)自动注册DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter
(2)提供一些列:数据绑定,数字和日期的format @NumberFormat, @DateTimeFormat, xml,json默认读写支持
-->
<mvc:annotation-driven />
<!-- use-default-filters="false" 只扫描指定的注解 -->
<context:component-scan base-package="com.ssm.controller" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 2.静态资源默认servlet配置
(1)加入对静态资源的处理:js,gif,png
(2)允许使用"/"做整体映射
-->
<mvc:default-servlet-handler/>
<!-- 3.配置jsp 显示ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 4.扫描web相关的bean -->
<context:component-scan base-package="com.ssm.controller" />
<!-- 5.文件上传需要的配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="512000000"/>
</bean>
</beans>
6、配置日志文件
#log4j.logger.org.hibernate.tool.hbm2ddl=debug
log4j.rootLogger=info,Console,R
log4j.addivity.org.apache=true
log4j.logger.com.zhiyin.mes.log.normal=debug,R
log4j.logger.com.zhiyin.mes.log.debug=debug,Console
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=${MySSM.root}/../logs/MySSM.log
log4j.appender.R.Encoding=utf-8
log4j.appender.R.MaxFileSize=20MB
log4j.appender.R.Append=true
log4j.appender.R.MaxBackupIndex=108
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d %-5p [%t][%C %L] %m%n
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
#log4j.appender.Console.layout.ConversionPattern=ConSole: %d [%t] %-5p [%c] - %m%n
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%C %L] - %m%n
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
#log4j.logger.org.apache=ERROR
log4j.logger.java.sql.Connection = DEBUG
log4j.logger.java.sql.Statement =DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG
#log4j.logger.java.sql.ResultSet = ERROR
log4j.logger.org.hibernate=INFO
#log4j.logger.org.hibernate.hql.ast.AST=ERROR
#log4j.logger.org.hibernate.SQL=ERROR
#log4j.logger.org.hibernate.type=ERROR
#log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=ERROR
#log4j.logger.org.hibernate.hql=ERROR
#log4j.logger.org.hibernate.cache=ERROR
#log4j.logger.org.hibernate.transaction=ERROR
#log4j.logger.org.hibernate.jdbc=ERROR
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=ERROR
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.com.zhiyin.dao = TRACE
log4j.logger.com.zhiyin.dao = INFO
7、最后一步配置web.xml文件,该文件用于加载spring的监听,过滤字符等一系列在初始化时就要触发的操作。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置log日志 -->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>MySSM.root</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!--Spring 监听 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 字符过滤-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
整个配置到此就结束,接下来,针对以上配置进行一些操作,用于验证配置是否正确。
三、实现通用的增删改查方法
1、全局意识
我们在进行编码之前,首先需要想到,是不是有些代码可以重用?是否可以提取一些公用的东西,不管是这个项目还是以后得项目都可以使用?我们是否要考虑数据的完整性?等等,都是我们需要在开始写代码之前考虑的问题。如果之前没有考虑好,等进行一段时间的编码过后,再想到提取,那样只会浪费时间。因此,在这个项目结构中,不管是service还是dao,或者是controller,我都先设计了Base*这一层,在我们需要实现业务逻辑时,继承base类,则可以省去很多的功夫。
2、IBaseDao.java 和其所对应的BaseMapper.xml
IBaseDao.java文件
package com.ssm.dao.base;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface IBaseDao {
/** 插入方法 **/
int insert(Map map);
/** 更新方法 **/
int update(Map map);
/** 通过id 查找对应数据 **/
Map findById(@Param("tablename") String tableName, @Param("id") Integer id);
/** 获取所有记录 **/
List<Map> findAll(@Param("tablename")String tableName,@Param("issoftdel")String isSoftDel);
/** 硬删除,删除后数据库记录消失 **/
int deleteById(@Param("tablename")String tableName,@Param("id")Integer id);
/** 软删除,更新是否删除标记 **/
int deleteSoftById(@Param("tablename")String tableName,@Param("id")Integer id);
/** 通过条件查询数据,用于校验是否重复 **/
List<Map> findByCondition(Map params);
/** 通过表名获取下一个id **/
int findNextId(@Param("tablename")String tableName);
}
对应的BaseMapper.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"classpath://mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.dao.base.IBaseDao">
<insert id="insert" parameterType="Map" keyProperty="id">
insert into ${tablename}
<foreach collection="fields" index="key" item="val" separator="," open="(" close=")">
${key}
</foreach>
values
<foreach collection="fields" index="key" item="val" separator="," open="(" close=")">
<if test=" key== 'id'">
${val}
</if>
<if test=" key != 'id'">
#{val}
</if>
</foreach>
</insert>
<update id="update" parameterType="Map">
update ${tablename} set
<foreach collection="fields" index="key" item="val" separator=",">
<if test=" key != null and key !='id'">${key}=#{val}</if>
</foreach>
where id = ${id}
</update>
<select id="findById" resultType="Map" parameterType="Map">
select * from ${tablename} where id = #{id}
</select>
<select id="findAll" resultType="Map" parameterType="Map">
select a.* from ${tablename} a
where 1 =1
<if test="issoftdel != null and issoftdel != '' and issoftdel == 'false'">
and a.delflag != 1
</if>
</select>
<delete id="deleteById" parameterType="Map">
delete from ${tablename} where id = #{id}
</delete>
<update id="deleteSoftById" parameterType="Map">
update ${tablename} set delflag = 1
where id = #{id}
</update>
<select id="findByCondition" resultType="Map" parameterType="Map">
select * from ${tablename} a
where a.${code} = #{value}
<if test="issoftdel != null and issoftdel != '' and issoftdel =='false'">
and a.delflag != 1
</if>
</select>
<select id="findNextId" parameterType="Map" resultType="int">
select ifnull(max(id),0)+1 from ${tablename}
</select>
</mapper>
在这里,我对于增删改查进行了统一的封装,其中有一点需要说明的是,我设计的数据库每一个基表都会有一个DelFlag字段,这个字段的作用在于我们删除的时候,决定是否是真正的删除(软删除和硬删除),即是否真正的从数据库中将记录删除掉。如果是真正的删除,则无法重新找回相应的记录,软删除的效果在于,如果何时,记录都在,只是有一个标记标记它这条记录是否应该被查询或者被校验。
2、BaseService.java
package com.ssm.service.base;
import com.ssm.dao.base.IBaseDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class BaseService {
@Autowired
private IBaseDao iBaseDao;
/***
* 插入方法
* @param cls bean class
* @param beanObj bean 对象
* @param tableName 表名
* @return int
* @throws Exception 异常
*/
public int insertSimple(Class cls, Object beanObj, String tableName){
Map<String,Object> para = new HashMap<String,Object>();
this.buildBeanAttrPara(cls, beanObj, para);
para.put("tablename", tableName);
return iBaseDao.insert(para);
}
/***
* 更新方法
* @param cls bean class
* @param fromObj bean 对象
* @param toObj bean 对象
* @param tableName 表名
* @return int
* @throws Exception 异常
*/
public int updateSimple(Class cls, Object fromObj, Object toObj, String tableName, Object id) throws Exception {
this.assignBeanAttrPara(cls, fromObj, toObj);
Map para = new HashMap();
para.put("id", id);
this.buildBeanAttrPara(cls, toObj, para);
para.put("tablename", tableName);
return this.iBaseDao.update(para);
}
/**
* 通过Id 查找数据
* @param tableName 表名
* @param id id
* @return map
*/
public Map findById(String tableName,Integer id){
return iBaseDao.findById(tableName,id);
}
/**
* 查找表中所有的数据
* @param tableName 表名
* @param isSoftDel 是否包含软删除,true:包含,false:不包含
* @return list
*/
public List<Map> findAll(String tableName,boolean isSoftDel){
return iBaseDao.findAll(tableName,Boolean.toString(isSoftDel));
}
/**
* 通过id删除数据
* @param tableName 表名
* @param id id
* @param isSoftDel 是否是软删除
* @return int
*/
public int deleteById(String tableName,Integer id,boolean isSoftDel){
if(isSoftDel){
return iBaseDao.deleteSoftById(tableName,id);
}else{
return iBaseDao.deleteById(tableName,id);
}
}
/***
* 校验在table中是否存在重复记录
* @param tableName 需要校验的记录表
* @param condition 表字段
* @param value 值
* @param isSoftDel 是否校验软删除,true:包含软删除,false:不包含软删除
* @return boolean ,true:重复,false:未重复
*/
public boolean checkIsDuplicate(String tableName,String condition,String value,boolean isSoftDel){
Map<String,String> map = new HashMap<String, String>();
map.put("tablename",tableName);
map.put("condition",condition);
map.put("value",value);
map.put("issoftdel",String.valueOf(isSoftDel));
List<Map> list = iBaseDao.findByCondition(map);
if(list.size() >0 ){
return true;
}else{
return false;
}
}
public int getId(String tableName){
return iBaseDao.findNextId(tableName);
}
/**
* 将一个 Map 对象转化为一个 JavaBean
* @param type 要转化的类型
* @param map 包含属性值的 map
* @return 转化出来的 JavaBean 对象
* @throws IntrospectionException 如果分析类属性失败
* @throws IllegalAccessException 如果实例化 JavaBean 失败
* @throws InstantiationException 如果实例化 JavaBean 失败
* @throws InvocationTargetException 如果调用属性的 setter 方法失败
*/
@SuppressWarnings("rawtypes")
public static Object convertFromMap(Class type, Map map)
throws IntrospectionException, IllegalAccessException,
InstantiationException, InvocationTargetException
{
BeanInfo beanInfo = Introspector.getBeanInfo(type); // 获取类属性
Object obj = type.newInstance(); // 创建 JavaBean 对象
// 给 JavaBean 对象的属性赋值
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (int i = 0; i< propertyDescriptors.length; i++) {
PropertyDescriptor descriptor = propertyDescriptors[i];
String propertyName = descriptor.getName();
Class propType = descriptor.getPropertyType();
if (map.containsKey(propertyName.toLowerCase())) {
// 下面一句可以 try 起来,这样当一个属性赋值失败的时候就不会影响其他属性赋值。
Object value = map.get(propertyName.toLowerCase());
if (value.equals(""))
continue;
Class valType = value.getClass();
if (valType.equals(BigDecimal.class) && (propType.equals(Integer.class) || propType.equals(int.class))) {
value = Integer.parseInt(value.toString());
}
if (valType.equals(String.class) && (propType.equals(Integer.class) || propType.equals(int.class))) {
value = Integer.parseInt(value.toString());
}
if (valType.equals(String.class) && (propType.equals(Double.class) || propType.equals(double.class))) {
value = Double.parseDouble(value.toString());
}
Object[] args = new Object[1];
args[0] = value;
descriptor.getWriteMethod().invoke(obj, args);
}
}
return obj;
}
/***
* 将bean转换成map,用于保存数据到数据库
* @param cls bean class
* @param obj bean 对象
* @param para map
* @throws Exception 异常
*/
public void buildBeanAttrPara(Class cls, Object obj, Map para){
Field[] fields = cls.getDeclaredFields();
Field.setAccessible(fields, true);
Map<String,Object> keyVal = new HashMap();
Field[] var9 = fields;
int var8 = fields.length;
try {
for(int var7 = 0; var7 < var8; ++var7) {
Field field = var9[var7];
keyVal.put(field.getName().toLowerCase(), field.get(obj));
}
}catch (Exception e){
e.printStackTrace();
}
para.put("fields", keyVal);
}
public void assignBeanAttrPara(Class cls, Object from, Object to) throws Exception {
Field[] fields = cls.getDeclaredFields();
Field.setAccessible(fields, true);
new HashMap();
Field[] var9 = fields;
int var8 = fields.length;
for(int var7 = 0; var7 < var8; ++var7) {
Field field = var9[var7];
Object val = field.get(from);
if (val != null) {
field.set(to, val);
}
}
}
}
代码部分有详细的注释,这里需要说明的是 插入和更新 这两个方法。我们利用javabean 和map的转换关系,实现通用的插入和更新的方法。因此,我们在插入或者更新时,都会依赖于javabean 对象,如果在我们得javabean中,没有将数据库中的字段写全,即实体类与表结构对应不上,将会抛出异常。
实现插入的具体思想是,通过获取Class的属性,和属性对应的值,进行map的创建,对应到mapper中,循环所有的对象属性,拼接插入的sql 语句,从而达到目的。
3、BaseController.java实现
package com.ssm.controller;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class BaseController {
public static Map getParameterMap(HttpServletRequest request) {
Map properties = request.getParameterMap();
Map<String,Object> returnMap = new HashMap<String, Object>();
Iterator entries = properties.entrySet().iterator();
String name = "";
String value = "";
while(entries.hasNext()) {
Map.Entry entry = (Map.Entry)entries.next();
name = (String)entry.getKey();
Object valueObj = entry.getValue();
if (valueObj == null) {
value = "";
} else if (!(valueObj instanceof String[])) {
value = valueObj.toString();
} else {
value = "";
String[] values = (String[])valueObj;
for (String v :values) {
value = value + v +",";
}
value = value.substring(0, value.length() - 1);
}
value = value.trim();
returnMap.put(name, value);
}
return returnMap;
}
}
在这里,我只将通过request获取参数并返回Map的方法提取出来,这样在具体的业务Controller中就可以直接通过该方法拿到一个Map类型的参数列表,实现简便化。
四、实现用户的增删改查操作
1、数据库表
CREATE TABLE IF NOT EXISTS `sys_user`(
`id` INT UNSIGNED AUTO_INCREMENT,
`name` VARCHAR(40) NOT NULL,
`password` VARCHAR(40) NOT NULL,
`phone` VARCHAR(11) NULL,
`delFlag` int default 0,
PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
2、User.java 对应的bean文件
package com.ssm.bean;
import java.io.Serializable;
public class User implements Serializable{
private Integer id;
private String name;
private String password;
private String phone;
private Integer delFlag = 0;
public User() {
}
public User(Integer id, String name, String password, String phone,Integer delFlag) {
this.id = id;
this.name = name;
this.password = password;
this.phone = phone;
this.delFlag = delFlag;
}
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 String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getDelFlag() {
return delFlag;
}
public void setDelFlag(Integer delFlag) {
this.delFlag = delFlag;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", phone='" + phone + '\'' +
", delFlag=" + delFlag +
'}';
}
}
3、UserService.java
package com.ssm.service.user;
import com.ssm.bean.User;
import com.ssm.dao.user.IUserDao;
import com.ssm.service.base.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserService extends BaseService{
private static final String tableName = "sys_user";
@Autowired
private IUserDao iUserDao;
/***
* 保存User信息
* @param user user
* @return Map
*/
public Map saveUser(User user){
// 通过手动获取id 的方法设置id
user.setId(getId(tableName));
// 插入数据库
int affected = insertSimple(User.class,user,tableName);
// 组织返回数据(此处可以设计一个用于返回的实体)
Map<String,Object> map = new HashMap<>();
if(affected == 1){
map.put("message","添加成功");
map.put("successful",1);
}else{
map.put("message","添加失败");
map.put("successful",0);
}
return map;
}
/***
* 保存User信息
* @param id id
* @return Map
*/
public Map deleteUser(int id ){
// 删除用户信息,第三个参数为 isSoftDel,代表软硬删除
int affected = deleteById(tableName,id,true);
// 组织返回数据(此处可以设计一个用于返回的实体)
Map<String,Object> map = new HashMap<>();
if(affected == 0) {
map.put("message","要删除的用户不存在");
map.put("successful",0);
}else{
map.put("message","删除成功");
map.put("successful",1);
}
return map;
}
public List<Map> queryAllUsers(Map params) throws Exception{
return findAll(tableName,false);
}
}
4、UserController.java
package com.ssm.controller.user;
import com.alibaba.fastjson.JSONObject;
import com.ssm.bean.User;
import com.ssm.controller.BaseController;
import com.ssm.service.user.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
@Controller
@RequestMapping("/SsmRoot/User")
public class UserController extends BaseController {
@Autowired
private UserService userService;
@RequestMapping(value = "/saveUser",method = {RequestMethod.GET,RequestMethod.POST})
@ResponseBody
public String saveUser(HttpServletRequest request, HttpServletResponse response) throws Exception{
JSONObject jsonObject = new JSONObject();
User user = new User();
user.setName("test");
user.setPassword("test");
user.setPhone("13122225555");
return jsonObject.toJSONString(userService.saveUser(user));
}
@RequestMapping(value = "/deleteUser",method = {RequestMethod.GET,RequestMethod.POST})
@ResponseBody
public String deleteUser(HttpServletRequest request, HttpServletResponse response) throws Exception{
JSONObject jsonObject = new JSONObject();
int id = 1;
return jsonObject.toJSONString(userService.deleteUser(id));
}
@RequestMapping(value = "/queryAllUses",method = {RequestMethod.GET,RequestMethod.POST})
@ResponseBody
public String queryAllUsers(HttpServletRequest request, HttpServletResponse response) throws Exception{
Map params = getParameterMap(request);
JSONObject jsonObject = new JSONObject();
return jsonObject.toJSONString(userService.queryAllUsers(params));
}
}
5、index.jsp
<%--
Created by IntelliJ IDEA.
User: ASUS
Date: 2018/3/31
Time: 15:31
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/tools/jquery/jquery.min.js"></script>
<script>
function onSave() {
$.post("../SsmRoot/User/saveUser",{},function (data) {
console.log(data);
$("#text").html(data);
})
}
function onDelete() {
$.post("../SsmRoot/User/deleteUser",{},function (data) {
console.log(data);
$("#text").html(data);
})
}
function onQuery() {
$.post("../SsmRoot/User/queryAllUses",{},function (data) {
console.log(data);
$("#text").html(data);
})
}
</script>
</head>
<body>
<input type="button" onclick="onSave()" name="增加" value="增加">
<input type="button" onclick="onDelete()" name="删除" value="删除">
<input type="button" onclick="onQuery()" name="请求" value="查询所有数据">
<br/>
<br/>
<br/>
<br/>
<textarea name="text" id="text" cols="90" rows="30"></textarea>"
</body>
</html>
五、验证
1、验证增加
初始查询数据库结果为0行。
点击增加按钮两次:
可以看到已经有两条数据产生。
2、验证查询数据
点击查询所有数据按钮,查询结果如上所示。
3、验证删除
点击删除后,再次查询数据,只有一条结果。
查询数据库:
可以看到这里用的是软删除标记,数据库中仍有两条数据。
六、总结
作为一个开发人员,首先应该有一个全局的把握,否则会给自己找来很多不必要的麻烦。
其次,关于框架的条条框框不是靠死记硬背,只有理解了其中的奥秘,才能遇到问题迎刃而解。
最后,祝大家学习愉快。
代码已经上传到csdn,如有需要请下载:MySSM