基于注解和xml配置的SSM(Spring+SpringMVC+Mybatis)项目详细配置

第一步、配置pom.xml

在一个ssm项目中,可能需要用到的依赖比较多,在这里先列举出来:

<!-- 属性配置 -->
<properties>
    <!-- 设置项目的编码 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- 设置java的版本为1.8-->
    <java.version>1.8</java.version>
    <!-- 源码编译的版本为1.8-->
    <maven.compiler.source>1.8</maven.compiler.source>
    <!-- 目标字节码的版本为1.8-->
    <maven.compiler.target>1.8</maven.compiler.target>
    <!-- 指定编译器版本为1.8-->
    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>

    <!-- 依赖的版本号 -->
    <spring.version>5.1.5.RELEASE</spring.version>
    <junit.version>4.12</junit.version>
    <mysql.version>5.1.47</mysql.version>
    <mybatis.version>3.5.2</mybatis.version>
    <mybatis.spring.version>2.0.3</mybatis.spring.version>
    <druid.version>1.1.20</druid.version>
    <project.version>1.0-SNAPSHOT</project.version>
    <servlet.version>4.0.1</servlet.version>
    <jackson.version>2.10.0</jackson.version>
    <pagehelper.version>5.1.10</pagehelper.version>
    <logback.version>1.2.3</logback.version>
</properties>
<!-- 添加依赖 -->
<dependencyManagement>
    <dependencies>
        <!-- 测试 -->
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- mysql驱动 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- spring -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- spring mvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- spring jdbc -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- druid连接池 -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!-- 事务管理 -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <!-- mybatis整合插件 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis.spring.version}</version>
        </dependency>
        <!-- Jackson -->
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- servlet -->
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- 分页插件 -->
        <!-- pagehelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>${pagehelper.version}</version>
        </dependency>
        <!-- 日志框架 -->
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
        <!-- 日志 -->
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
    </dependencies>
</dependencyManagement>

第二步、dao层配置

在dao层中,主要就是配置连接池,mybatis和分页插件

1、创建包:

创建如下:

2、实现业务类:

City.java:

public class City {
    
    private String cityId;
    private String cityName;
    private String cityCode;
    private String province;
}

CityDao.java:

public interface CityDao {

    /**
     * 分页,获取城市信息
     * @param pageNum 第几页(从0开始)
     * @param pageSize 每页几条
     * @return
     */    
    List<City> cityInfo(@Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize);

    /**
     * 获取指定城市信息
     * @param cityId 城市id
     * @return
     */
    City getCity(String cityId);
}

3、创建xml配置文件和mapper映射文件

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:mybatis="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
    
    <!-- 启用注解相关的后置处理器,这样才可以在代码中使用Spring提供的相关注解 -->
    <!-- <context:annotation-config /> -->

    <!-- 配置包扫描,也就是扫描哪些包下带有注解的类,将其纳入ioc容器管理,
    base-package属性将会扫描当前包以及子包下所有的类
    注意:当配置了component-can,那么就不需要再配置annotation-config,
    因为component-scan已经包含了-->
    <context:component-scan base-package="edu.nf.xml" >
        <context:exclude-filter type="aspectj" expression="edu.nf.xml.controller"/>
    </context:component-scan>
    
    <!-- 配置数据源,这里使用druid连接池,(alibaba)开源,所有的连接池都会实现了DataSource接口的规范,
    下面就是将druid与spring整合,将连接池纳入spring容器中管理。
    注意:druid是可以单独使用,并不一定要整合到spring中,只是通常用到Spring框架都会与数据源进行整合 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 设置数据库的连接属性 -->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;encoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <!-- 连接池属性配置 -->
        <!-- 连接池最大连接池数量 -->
        <property name="maxActive" value="200"/>
        <!-- 初始化连接池时的连接数量 -->
        <property name="initialSize" value="2"/>
        <!-- 最小连接数量 -->
        <property name="minIdle" value="5"/>
        <!-- 获取连接的等待时间,单位:毫秒 -->
        <property name="maxWait" value="60000"/>
        <!-- 连接保持空闲而不被驱逐的最小时间(在规定时间内如果连接未被使用,则被驱逐连接池,直到最小连接数量) -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>
        <!-- 检测连接,如果检测到连接空闲时间大于timeBetweenEvictionRunsMillis的值,
         则关闭物理连接 -->
        <property name="timeBetweenEvictionRunsMillis" value="6000"/>
        <!-- 申请连接时检测,如果空余时间大于timeBetweenEvictionRunsMillis指定的时间,
        就执行validationQuery检测连接是否有效 -->
        <property name="testWhileIdle" value="true"/>
        <!-- 伪sql语句,用于检查连接是否有用 -->
        <property name="validationQuery" value="select 1"/>
        <!-- 申请连接时执行validationQuery检测连接是否有用,默认true,建议设置false,提高性能 -->
        <property name="testOnBorrow" value="false"/>
        <!-- 归还连接时是否检测连接是否可用 -->
        <property name="testOnReturn" value="false"/>
        <!-- 是否缓存PreparedStatement,MySQL或Oracle建议关闭 -->
        <property name="poolPreparedStatements" value="false"/>
    </bean>

    <!-- 整合mybatis,配置SqlSessionFactoryBean,它将负责创建SqlSessionFactory交由容器管理 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 给实体包下的类定义默认的别名 -->
        <property name="typeAliasesPackage" value="edu.nf.ch04.entity"/>
        <!-- 指定mapper映射目录 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        <!-- 配置分页插件-->
        <property name="plugins">
            <!-- 配置分页插件的拦截器 -->
            <bean class="com.github.pagehelper.PageInterceptor">
                <!-- 配置拦截器属性 -->
                <property name="properties">
                    <props>
                        <!-- 指定数据库方言 -->
                        <prop key="helperDialect">mysql</prop>
                        <!-- 分页参数注解支持-->
                        <prop key="supportMethodsArguments">true</prop>
                        <!-- 分页合理化-->
                        <prop key="rowBoundsWithCount">true</prop>
                    </props>
                </property>
            </bean>
        </property>
    </bean>

    <!-- 指定扫描的dao接口包,
    mybatis插件会根据这些接口自动创建相应的实现类,
    底层基于动态代理来创建dao接口的实现类 -->
    <mybatis:scan base-package="edu.nf.xml.dao"/>

</beans>

CityServiceMapper.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="edu.nf.xml.dao.CityDao">
    <resultMap id="cityMap" type="edu.nf.xml.entity.City">
        <id column="city_id" property="cityId"/>
        <result column="city_name" property="cityName"/>
        <result column="city_code" property="cityCode"/>
        <result column="province" property="province"/>
    </resultMap>

    <select id="cityInfo" resultMap="cityMap">
        select city_id, city_name, city_code, province from city_info
    </select>

    <select id="getCity" resultMap="cityMap" parameterType="String">
        select city_id, city_name, city_code, province from city_info where city_id = #{cityId}
    </select>

</mapper>

到这里,dao层已经基本配置完毕,现在开始配置service层和controller层

第三步:service层配置

service层主要做事务管理和aop切面

1、创建包:

2、实现业务类:

CityService.java

public interface CityService {

    /**
     * 分页,获取城市信息
     * @param pageNum 第几页(从0开始)
     * @param pageSize 每页几条
     * @return
     */
    PageInfo<City> cityInfo(@Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize);

    /**
     * 获取指定城市信息
     * @param cityId 城市id
     * @return
     */
    City getCity(String cityId);
}

CityServiceImpl.java:实现CityService接口,dao会在运行时动态生成生成代理实现类而注入

@Service
@Transactional(rollbackFor = DataAccessException.class)
public class CityServiceImpl implements CityService {

    @Autowired
    private CityDao dao;

    /**
     * 分页:获取城市信息
     * @param pageNum 第几页(从0开始)
     * @param pageSize 每页几条
     * @return 返回分页信息
     */
    @Override
    public PageInfo<City> cityInfo(Integer pageNum, Integer pageSize) {
        try {
            List<City> list = dao.cityInfo(pageNum, pageSize);
            PageInfo pageInfo = new PageInfo(list);
            return pageInfo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataAccessException("获取城市列表失败");
        }
    }

    /**
     * 获取指定城市信息
     * @param cityId 城市id
     * @return
     */
    @Override
    public City getCity(String cityId) {
        try {
            return dao.getCity(cityId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataAccessException("获取城市信息失败");
        }
    }
}

DataAccessException.java:自定义异常类,继承自RunTimeException

public class DataAccessException extends RuntimeException {

    public DataAccessException() {
        super();
    }

    public DataAccessException(String message) {
        super(message);
    }

    public DataAccessException(String message, Throwable cause) {
        super(message, cause);
    }
}

CityAspect.java:切面类(spring-study ch11-ch14)

public class UserServiceAspect {

    /**
     * 前置通知
     * @param jp 连接点,通过这个连接点可以获取目标方法
     */
    public void before(JoinPoint jp){
        System.out.println("前置通知,目标方法参数:" + jp.getArgs()[0]);
    }

    /**
     * 环绕通知
     * @param pjp 连接点,可以获取目标方法参数以及方法信息以及调用目标方法等等
     */
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕通知前。。。");
        //获取目标方法的的Method对象
        MethodSignature ms = (MethodSignature)pjp.getSignature();
        Method method = ms.getMethod();
        System.out.println("当前调用的目标方法:" + method.getName());
        //调用目标方法
        Object returnVal = pjp.proceed();
        System.out.println("环绕通知后。。。");
        return returnVal;
    }

    /**
     * 后置通知
     * @param returnVal 目标方法的返回值
     */
    public void afterReturning(String returnVal){
        System.out.println("后置通知,返回参数:" + returnVal);
    }

    /**
     * 异常通知
     * @param e 目标方法产生的异常对象
     */
    public void afterThrowing(Throwable e){
        System.out.println("异常通知,异常信息:" + e.getMessage());
    }

    /**
     * 最终通知
     */
    public void after(){
        System.out.println("最终通知");
    }
}

要在applicationContext.xml配置文件中添加以下配置:

<!-- 定义切面 -->
<bean id="cityAspect" class="edu.nf.xml.service.aspect.CityAspect"/>

<!-- 配置aop,基于AspectJ -->
<aop:config>
    <aop:pointcut id="myPointcut" expression="execution(* edu.nf.xml.service.impl.CityServiceImpl.*(..))"/>
    <aop:aspect ref="cityAspect">
        <!-- 装配通知,method对应通知的方法名,pointcut-ref引用上面定义的切入点的id
             如果不同的通知想使用不同的切入点,那么使用pointcut属性进行的自定义 -->
        <!-- 前置通知 -->
        <aop:before method="before" pointcut-ref="myPointcut"/>
        <!-- 环绕通知 -->
        <aop:around method="around" pointcut-ref="myPointcut"/>
        <!-- 后置通知,returnVal属性指定后置通知方法的参数名(参数名称要一致) -->
        <aop:after-returning method="afterReturning" pointcut-ref="myPointcut" returning="returnVal"/>
        <!-- 异常通知,throwing属性指定异常通知方法的参数名(名称要一致) -->
        <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="e"/>
        <!-- 最终通知 -->
        <aop:after method="after" pointcut-ref="myPointcut"/>
    </aop:aspect>
</aop:config>

3、添加配置:

在applicationContext.xml配置文件中添加以下配置:

<!-- 装配事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 注入数据源 -->
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 启用事务注解处理器 -->
<tx:annotation-driven transaction-manager="txManager"/>

4、测试:

CityTest.java,在test模块中创建测试类:

public class CityTest {

    @Test
    public void testListCity(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        CityService service = context.getBean("cityService", CityService.class);
        PageInfo<City> pageInfo = service.cityInfo(0, 5);
        List<City> list = pageInfo.getList();
        list.forEach(city -> System.out.print(city.getCityName() + "++"));
    }
}

运行结果:

第四步:controller层配置

controller主要有处理请求的方法,全局异常处理,拦截器等与springmvc相关的配置

1、创建包和类,及web构面

2、实现业务类:

ControllerAspect.java:全局异常处理,在service层中可能回抛出DataAccessException异常,在这个类中可以处理:

@ControllerAdvice("edu.nf.xml.controller")
public class ControllerAspect {

    @ExceptionHandler(DataAccessException.class)
    @ResponseBody
    public ResponseVO handleDataAccessException(DataAccessException e){
        ResponseVO vo = new ResponseVO();
        vo.setCode(500);
        vo.setMessage(e.getMessage());
        return vo;
    }

}

LoginInterceptor.java:拦截器(springmvc-study ch10*),这里是用作登录拦截,在写拦截器类前需要添加配置信息:

<!-- 配置拦截器 -->
<mvc:interceptors>
    <!-- 可以配置多个拦截器 -->
    <mvc:interceptor>
        <!-- 指定哪些url是需要被拦截的 -->
        <mvc:mapping path="/***"/>
        <!-- 配出哪些请求不需要被拦截 -->
        <mvc:exclude-mapping path="/login.html"/>
        <mvc:exclude-mapping path="/user_login"/>
        <mvc:exclude-mapping path="/js/**"/>
        <!-- 配置自定义的拦截器 -->
        <bean class="edu.nf.xml.controller.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 调用controller方法之前调用
     * @param request
     * @param response
     * @param handler 目标控制器实例
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("调用controller方法前。。。");
        HttpSession session = request.getSession();
        if(session.getAttribute("user") == null){
            //如果没登录,则重定向回登录页面
            response.sendRedirect("login.html");
            //返回false,阻止后面的方法执行
            return false;
        }
        return true;
    }

    /**
     * 再调用controller方法之后执行,但未返回ModelAndView时执行
     * 注意:只有再preHandle方法返回true的情况下才会执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("调用controller方法之后。。。");
    }

    /**
     * 方法返回后,视图响应之前调用此方法,在返回ModelAndView后执行
     * 注意:这个方法只有在preHandle方法返回true的时候才能调用
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("响应视图。。。");
    }
}

CityController.java:请求处理器

@RestController
@RequestMapping("/city")
public class CityController extends BaseController {

    @Autowired
    private CityService service;

    /**
     * 查询城市列表
     * @param pageNum
     * @param pageSize
     * @return
     */
    @GetMapping("/city")
    public ResponseVO listCity(Integer pageNum, Integer pageSize){
        PageInfo<City> pageInfo = service.cityInfo(pageNum, pageSize);
        System.out.println(pageInfo.getList());
        return success(pageInfo);
    }

    /**
     * 获取城市信息
     * @param cityId
     * @return
     */
    @GetMapping("/${cityId}")
    public ResponseVO cityInfo(@PathVariable("cityId") String cityId){
        City city = service.getCity(cityId);
        System.out.println(city);
        return success(city);
    }
}

3、添加配置

dispatcher-serverlt.xml:在controller层中,主要做servlet的配置

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 扫描,只负责扫描controller中的类 -->
    <context:component-scan base-package="edu.nf.xml.controller"/>

    <!-- mvc注解 -->
    <mvc:annotation-driven/>

    <!-- 静态资源 -->
    <mvc:default-servlet-handler/>

    <!-- 内部视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 方式一:导入applicationContext.xml配置文件 -->
    <!--    <import resource="applicationContext.xml"/>-->
</beans>

添加了web构面后,在web/WEB-INF目录下就会有一个web.xml配置文件,在这里配置DispatcherServlet和applicationContext.xml

<!-- 配置一个上下文监听器,这个是由spring提供的
     注意:监听器会优先于Servlet初始化,因此当监听器初始化一个配置文件时,
     会创建一个ioc容器,这个容器就是主容器,而下面通过DispatcherServlet创建的容器
     就会自动设置为当前容器的子容器,这就是父子容器的概念,当我们要从容器中获取一个bean对象时,
     先从子容器中查找,如果没有则到父容器中查找,反过来,父容器是不能访问子容器的内容。-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

<!-- spring提供的字符编码过滤器 -->
<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>
    <!-- 将request和response的编码保持一致 -->
    <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>

<!-- 配置核心控制器 servlet-->
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

4、测试:

使用ajax异步请求,测试获取城市列表请求:

发送请求:

<script>
    $(function(){
        $.ajax({
            url:'city/list_city',
            data: {'pageNum': 0, 'pageSize': 5},
            type:'post',
            success: function(result){
                console.log(result);
            }
        })
    })
</script>

结果:

猜你喜欢

转载自www.cnblogs.com/zhangcaihua/p/12803270.html