SMM整合

文章目录

    • 后台
      • SpringMVC
        • 导入依赖
        • 配置`web.xml`
        • `springMVC.xml`配置文件
        • 编写Controller测试
      • Spring核心整合
        • 创建多个模块的配置文件
        • 配置`web.xml`(***)
        • `applicationContext.xml`配置文件
        • 测试
      • SpringAOP开发
        • 导入依赖
      • `applicationContext-aop.xml`配置文件
        • 切面类
        • 测试
        • SpringAOP切面类不运行的问题
      • MyBatis整合
        • 导入依赖
        • `applicationContext-mybatis.xml`配置文件
          • `db.properties`配置文件
          • maven打包问题
        • 测试
        • 配置事务
        • 配置二级缓存
          • 导入依赖
          • `memcached.properties`
          • 在`UserMapper.xml`映射文件中应用缓存
          • `mybatis-config`配置文件
        • 分页插件
          • 导入依赖
          • 在`mybatis-config`配置文件中配置插件
          • Controller层和Service层更改
        • 测试
      • 完善功能
        • 配置日志
          • 导入依赖
          • 配置文件
          • 在`mybatis-config.xml`文件中增加设置
        • 参数校验
          • 导入依赖
          • 为实体类属性增加校验
          • 控制器中的方法
        • 全局异常处理
          • 编写异常处理类
          • Controller中的修改
        • 增加拦截器
          • 导入依赖
          • 创建拦截器
          • 在`springMVC.xml`中配置拦截器
      • 完善所有层中的方法
        • Controller层
        • Service层
      • 关于resource目录下文件不存在的问题
    • 文档
      • 操作步骤
        • 导入依赖
        • Swagger配置类
        • 生成文档
      • 一些注解

后台

SpringMVC

导入依赖

pom.xml文件中增加依赖



<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>5.1.9.RELEASEversion>
dependency>


<dependency>
    <groupId>com.fasterxml.jackson.coregroupId>
    <artifactId>jackson-databindartifactId>
    <version>2.11.0version>
dependency>

SMM整合_第1张图片

从依赖关系可得,spring-webmvcjar包中存在Spring的很多依赖,注意不要重复导入依赖

配置web.xml


<filter>
    <filter-name>characterEncodingFilterfilter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
filter>

<filter>
    <filter-name>hiddenHttpMethodFilterfilter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>

<filter-mapping>
    <filter-name>characterEncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>
<filter-mapping>
    <filter-name>hiddenHttpMethodFilterfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>



<servlet>
    <servlet-name>dispatcherServletservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    
    <init-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath:springMVC.xmlparam-value>
    init-param>
    
    <load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
    <servlet-name>dispatcherServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>

springMVC.xml配置文件

<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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    
    <context:component-scan base-package="com.young" use-default-filters="false">
        
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    
    <mvc:default-servlet-handler/>

    
    <mvc:annotation-driven/>

    

    
    
beans>

编写Controller测试

@RestController
@RequestMapping("user")
public class UserController {
    @GetMapping("test")
    public AjaxData test(){
        System.out.println("测试成功");
        AjaxData ajaxData = new AjaxData();
        ajaxData.setDatas("测试成功");
        return ajaxData;
    }
}

AjaxData类作为返回json数据的封装类

public class AjaxData {
    private boolean success=true;	//默认为true,可以不用每次都使用set方法设置
    private Object datas;
    private Object msg;		//错误原因可能很多,可能返回一个存储错误原因的集合

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public Object getDatas() {
        return datas;
    }

    public void setDatas(Object datas) {
        this.datas = datas;
    }

    public String getMsg() {
        return msg;
    }

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

Spring核心整合

创建多个模块的配置文件

一个配置文件中完成以上操作,内容比较多,不容易管理,所以我们分别编写几个文件,做不同的事情。
SMM整合_第2张图片

配置web.xml(***)


<context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:applicationContext*.xmlparam-value>
context-param>



<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>

applicationContext.xml配置文件

注意父子容器问题,避免重复扫描


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

    
    <context:component-scan base-package="com.young">
        
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>
beans>

测试

IUserService接口

public interface IUserService {
    //测试方法
    void test();
}

UserService实现类

@Service
public class UserService implements IUserService {
    public void test(){
        System.out.println("UserServiceImpl test method invoke");
    }
}

UserController控制器

@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private IUserService userService;

    @GetMapping("test")
    public AjaxData test(){
        System.out.println("测试成功");
        userService.test();
        AjaxData ajaxData = new AjaxData();
        ajaxData.setDatas("测试成功");
        return ajaxData;
    }
}

SpringAOP开发

导入依赖


<dependency>
    <groupId>org.aspectjgroupId>
    <artifactId>aspectjweaverartifactId>
    <version>1.9.5version>
dependency>

applicationContext-aop.xml配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    
    <aop:aspectj-autoproxy/>
beans>

切面类

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

//将该类交给Spring容器
@Component
//声明该类为切面类
@Aspect
public class LogAspect {
    
    @Pointcut("execution(* com.young..*.*(..))")
    public void logPointCut(){}

    @Around(value = "logPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around start");
        long stime=System.currentTimeMillis();
        Object result = pjp.proceed(pjp.getArgs());
        long etime=System.currentTimeMillis();
        String cname = pjp.getTarget().getClass().getName();
        String mname = pjp.getSignature().getName();
        String logMsg = String.format("%s类%s方法执行时间为%s", cname, mname, (etime - stime));
        System.out.println(logMsg);
        return result;
    }
}

测试

运行程序,控制台输出日志信息。

SpringAOP切面类不运行的问题

在进行SSM整合时,出现了切面类无法运行的问题,问题如下:

配置文件内容
springMVC.xml配置文件

<context:component-scan base-package="com.young">
    
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>

applicationContext.xml配置文件

<context:component-scan base-package="com.young" >
    
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>

applicationContext-aop.xml配置文件

<aop:aspectj-autoproxy/>

原因

springMVC.xml配置文件开启扫描时需要配置属性:use-default-filters="false",不使用默认的Filter进行扫描

<context:component-scan base-package="com.young" use-default-filters="false">
    
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>

SpringMVC是Spring的子容器,如果在不配置use-default-filters="false",那么子容器会扫描@Component@Service@Reposity@Controller这四个注解标注的Bean,使Spring容器(父容器)无法扫描到@Component@Service@Reposity注解标注的类,如果Bean不交给Spring容器是无法应用切面类的。
可以将配置放入springMVC.xml配置文件中,此时切面类起作用。
当在springMVC.xml配置文件中配置use-default-filters="false",就不会使用默认的Filter进行扫描,在标签中配置只扫描@Controller注解标注的控制器。

避免方法

可以在测试时,为service层中的类提供一个构造方法

public UserService(){
    System.out.println("UserService run...");
}

如果SpringMVC容器会扫描service层中的类,那么控制台会输出两次以上输出语句,这就代表着父子容器重复扫描。这是一个很好的习惯!

MyBatis整合

导入依赖

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.18version>
dependency>

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-txartifactId>
    <version>5.1.9.RELEASEversion>
dependency>

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jdbcartifactId>
    <version>5.1.9.RELEASEversion>
dependency>

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.10version>
dependency>

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.4.6version>
dependency>


<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatis-springartifactId>
    <version>2.0.4version>
dependency>

applicationContext-mybatis.xml配置文件


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

    
    <context:property-placeholder location="classpath:db.properties"/>

    
    <bean id="druidDataSource" init-method="init" destroy-method="close" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
        <property name="url" value="${db.url}"/>
        <property name="driverClassName" value="${db.driverClassName}"/>
    bean>

    
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        
        <property name="dataSource" ref="druidDataSource"/>
               
        
        <property name="typeAliasesPackage" value="com.young.model"/>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.young.mapper"/>
    bean>
beans>
db.properties配置文件
db.url=jdbc:mysql://localhost:3306/mybatis_db?serverTimezone=UTC
db.username=root
db.password=123
db.driverClassName=com.mysql.jdbc.Driver
maven打包问题

<resources>
    <resource>
        <directory>src/main/javadirectory>
        <includes>
            <include>**/*.xmlinclude>
        includes>
    resource>
resources>

测试

使用插件一键生成实体类、Mapper接口以及Mapper映射文件

在Mapper接口中提供selectAll()方法查询所有数据,并在映射文件中提供相应的标签

在Service层中注入UserMapper类对象,并调用selectAll()方法,将数据返回给Controller,Controller中调用Service层中的方法,将数据返回给前端。

配置事务

applicationContext-tx.xml配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"/>
    bean>

    
    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            
            <tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
            <tx:method name="*"/>
        tx:attributes>
    tx:advice>

    
    <aop:config>
        
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.young..*.*(..))"/>
    aop:config>
beans>

配置二级缓存

导入依赖

<dependency>
    <groupId>org.mybatis.cachesgroupId>
    <artifactId>mybatis-memcachedartifactId>
    <version>1.0.0version>
dependency>
memcached.properties
#any string identifier
org.mybatis.caches.memcached.keyprefix=_biz-cache-wk_
#space separated list of ${host}:${port}
org.mybatis.caches.memcached.servers=127.0.0.1:11211
#org.mybatis.caches.memcached.servers=192.168.0.44:12000
#Any class that implementsnet.spy.memcached.ConnectionFactory
org.mybatis.caches.memcached.connectionfactory=net.spy.memcached.DefaultConnectionFactory
#the number of seconds in 30 days    the expiration time (in seconds)
org.mybatis.caches.memcached.expiration=6000
#flag to enable/disable the async get
org.mybatis.caches.memcached.asyncget=false
#the timeout when using async get
org.mybatis.caches.memcached.timeout=5
#the timeout unit when using async get
org.mybatis.caches.memcached.timeoutunit=java.util.concurrent.TimeUnit.SECONDS
#if true, objects will be GZIP compressed before putting them to
org.mybatis.caches.memcached.compression=false

#\u7f13\u5b58\u670d\u52a1\u5668\u5b95\u673a\u540e\u591a\u4e45\u4e0d\u4f7f\u7528memcached \u6beb\u79d2\u4e3a\u5355\u4f4d
#refuse time when connection refused
org.mybatis.caches.memcached.refuseperiod=1000
UserMapper.xml映射文件中应用缓存
<cache type="org.mybatis.caches.memcached.MemcachedCache"/>
mybatis-config配置文件


<configuration>
    <settings>
        
        <setting name="cacheEnabled" value="true"/>
    settings>
configuration>

需要在applicationContext-mybatis.xml配置文件中加载mybatis-config配置文件



<property name="configLocation" value="classpath:mybatis-config.xml"/>

分页插件

导入依赖

<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.1.11version>
dependency>
mybatis-config配置文件中配置插件
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
plugins>
Controller层和Service层更改

UserService类中selectAll()方法

@Override
public PageInfo<User> selectAll(Integer pageNum, Integer pageSize) {
    //如果页码和页面大小为空,那么指定大小
    if (pageNum==null){
        pageNum=1;
    }
    if (pageSize==null){
        pageSize=5;
    }
    PageHelper.startPage(pageNum,pageSize);
    List<User> list = userMapper.selectAll();
    PageInfo<User> userPageInfo = new PageInfo<>(list);
    return userPageInfo;
}

UserController类中selectAll()方法

//提供两种映射路径,支持全查和分页查询
@GetMapping(value = {"selectAll/{pageNum}/{pageSize}","selectAll"})
//设置required = false,使参数不是必须的
public AjaxData selectAll(@PathVariable(value = "pageNum",required = false) Integer pageNum,
                          @PathVariable(value = "pageSize",required = false) Integer pageSize){

    PageInfo<User> userPageInfo = userService.selectAll(pageNum, pageSize);
    AjaxData ajaxData = new AjaxData();
    ajaxData.setDatas(userPageInfo);
    return ajaxData;
}

测试

运行memcached.exe,准备测试二级缓存

运行程序,输入不同的映射路径,测试全查和分页查询

修改数据库中的数据,再次查询,发现返回结果没有发生改变,则缓存起作用

完善功能

配置日志

导入依赖

    <dependency>
      <groupId>log4jgroupId>
      <artifactId>log4jartifactId>
      <version>1.2.17version>
    dependency>
配置文件

<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        Console>
    Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        Root>
    Loggers>
Configuration>
mybatis-config.xml文件中增加设置

<setting name="logImpl" value="LOG4J"/>

参数校验

导入依赖

<dependency>
    <groupId>org.hibernate.validatorgroupId>
    <artifactId>hibernate-validatorartifactId>
    <version>6.1.2.Finalversion>
dependency>
为实体类属性增加校验
@NotNull(message = "请传递参数username",groups = {insertValidated.class, updateValidated.class})
@NotBlank(message = "请输入参数username",groups = {insertValidated.class, updateValidated.class})
private String username;

@NotNull(message = "请传递参数password",groups = {insertValidated.class, updateValidated.class})
@NotBlank(message = "请输入参数password",groups = {insertValidated.class, updateValidated.class})
@Length(min = 8,max = 16,message = "密码长度为8到16位",groups = {insertValidated.class})
private String password;

创建接口作为分组的依据:
在这里插入图片描述

控制器中的方法
@PostMapping("user/{username}/{password}")
public AjaxData insert(@Validated(value = {insertValidated.class}) User user, BindingResult errors){
    AjaxData ajaxData = new AjaxData();
    if (errors.hasErrors()){
        HashMap<String, String> map = new HashMap<>();
        List<FieldError> fieldErrors = errors.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            String fname = fieldError.getField();
            String msg = fieldError.getDefaultMessage();
            map.put(fname,msg);
        }
        ajaxData.setSuccess(false);
        ajaxData.setDatas(map);
        return ajaxData;
    }
    ajaxData.setDatas("添加成功");
    return ajaxData;
}

@PutMapping("user/{username}/{password}")
public AjaxData update(@Validated(value = {updateValidated.class}) User user, BindingResult errors){
    AjaxData ajaxData = new AjaxData();
    if (errors.hasErrors()){
        HashMap<String, String> map = new HashMap<>();
        List<FieldError> fieldErrors = errors.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            String fname = fieldError.getField();
            String msg = fieldError.getDefaultMessage();
            map.put(fname,msg);
        }
        ajaxData.setSuccess(false);
        ajaxData.setMsg(map);
        return ajaxData;
    }
    ajaxData.setDatas("更新成功");
    return ajaxData;
}

将控制器改为restful风格

//一个控制器中的映射路径相同,根据参数和请求方式的不同来对应不同的方法
@RequestMapping("api")

全局异常处理

在控制器的方法中,都需要进行异常处理,存在大量的代码冗余

编写异常处理类
import com.young.util.AjaxData;
import org.apache.log4j.Logger;
//注意BindException的包
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;


//标注该类为异常处理类
@ControllerAdvice
public class SpringMVCExecption {

    private Logger logger=Logger.getLogger(SpringMVCExecption.class);

    @ExceptionHandler(BindException.class)
    //使其返回json字符串
    @ResponseBody
    public AjaxData handlerBindExecpion(BindException e){
        AjaxData ajaxData = new AjaxData();
        ajaxData.setSuccess(false);
        BindingResult errors = e.getBindingResult();
        HashMap<String, String> map = new HashMap<>();
        List<FieldError> fieldErrors = errors.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            String fname = fieldError.getField();
            String msg = fieldError.getDefaultMessage();
            map.put(fname,msg);
            logger.error(fname+":"+msg);
        }
        ajaxData.setSuccess(false);
        ajaxData.setMsg(map);
        return ajaxData;
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public AjaxData handlerExecpion(Exception e){
        AjaxData ajaxData = new AjaxData();
        ajaxData.setSuccess(false);
        ajaxData.setMsg("服务器繁忙,请稍后再试");
        //将错误信息用日志记录,便于发现问题
        logger.error(e.getMessage());
        e.printStackTrace();
        return ajaxData;
    }
}
Controller中的修改
import com.github.pagehelper.PageInfo;
import com.young.model.validated.insertValidated;
import com.young.model.validated.updateValidated;
import com.young.model.User;
import com.young.service.IUserService;
import com.young.util.AjaxData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api")
public class UserController {

    @Autowired
    private IUserService userService;



    @DeleteMapping("user/{id}")
    public AjaxData delete(@PathVariable ("id")Integer id){
        userService.delete(id);
        AjaxData ajaxData = new AjaxData();
        ajaxData.setMsg("删除成功");
        return ajaxData;
    }

    @GetMapping(value = {"user/{pageNum}/{pageSize}","user"})
    public AjaxData selectAll(@PathVariable(value = "pageNum",required = false) Integer pageNum,
                              @PathVariable(value = "pageSize",required = false) Integer pageSize){
        PageInfo<User> userPageInfo = userService.selectAll(pageNum, pageSize);
        AjaxData ajaxData = new AjaxData();
        ajaxData.setDatas(userPageInfo);
        return ajaxData;
    }

    @PostMapping("user/{username}/{password}")
    public AjaxData insert(@Validated(value = {insertValidated.class}) User user, BindingResult errors) throws BindException {
        AjaxData ajaxData = new AjaxData();
        if (errors.hasErrors()){
            //此处抛出BindException以便于异常处理器接收
            throw new BindException(errors);
        }
        ajaxData.setDatas("添加成功");
        return ajaxData;
    }

    @PutMapping("user/{username}/{password}")
    public AjaxData update(@Validated(value = {updateValidated.class}) User user, BindingResult errors) throws BindException {
        AjaxData ajaxData = new AjaxData();
        if (errors.hasErrors()){
            throw new BindException(errors);
        }
        ajaxData.setDatas("更新成功");
        return ajaxData;
    }
}

增加拦截器

SpringMVC中的拦截器用于拦截controller方法的,可以记录日志

导入依赖

在创建拦截器时需要使用到javax.servlet包下的类及方法


<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>javax.servlet-apiartifactId>
    <version>4.0.1version>
    <scope>providedscope>
dependency>
创建拦截器
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SpringMVCLogInterceptor implements HandlerInterceptor {

    private Logger logger=Logger.getLogger(SpringMVCLogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long stime=System.currentTimeMillis();
        request.setAttribute("stime",stime);
        //return true表示继续执行,将请求发送到Controller层
        //如果return false,那么请求就会被拦截无法到达Controller层
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        long etime = System.currentTimeMillis();
        long stime = Long.parseLong(request.getAttribute("stime").toString());
        long time=etime-stime;
        StringBuffer requestURL = request.getRequestURL();
        String msg =String.format("%s资源,处理时间%s毫秒",requestURL,time);
        logger.debug(msg);
    }
}
springMVC.xml中配置拦截器
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.young.springmvc.interceptor.SpringMVCLogInterceptor"/>
    mvc:interceptor>
mvc:interceptors>

完善所有层中的方法

Controller层

UserController

import com.github.pagehelper.PageInfo;
import com.young.model.validated.insertValidated;
import com.young.model.validated.updateValidated;
import com.young.model.User;
import com.young.service.IUserService;
import com.young.util.AjaxData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api")
public class UserController {

    @Autowired
    private IUserService userService;

    //根据id删除用户
    @DeleteMapping("user/{id}")
    public AjaxData delete(@PathVariable ("id")Integer id){
        userService.deleteByPrimaryKey(id);
        AjaxData ajaxData = new AjaxData();
        ajaxData.setMsg("删除成功");
        return ajaxData;
    }

    @GetMapping(value = {"user/{pageNum}/{pageSize}","user"})
    public AjaxData selectAll(@PathVariable(value = "pageNum",required = false) Integer pageNum,
                              @PathVariable(value = "pageSize",required = false) Integer pageSize){
        PageInfo<User> userPageInfo = userService.selectAll(pageNum, pageSize);
        AjaxData ajaxData = new AjaxData();
        ajaxData.setDatas(userPageInfo);
        return ajaxData;
    }

    @GetMapping(value = "user/{id}")
    public AjaxData selectById(@PathVariable("id") Integer id){
        User user = userService.selectByPrimaryKey(id);
        AjaxData ajaxData = new AjaxData();
        ajaxData.setDatas(user);
        return ajaxData;
    }

    @PostMapping(value = "user/{username}/{password}")
    public AjaxData insert(@Validated(value = {insertValidated.class}) User user, BindingResult errors) throws BindException {
        AjaxData ajaxData = new AjaxData();
        if (errors.hasErrors()){
            throw new BindException(errors);
        }
        userService.insertSelective(user);
        ajaxData.setDatas("添加成功");
        return ajaxData;
    }

    @PutMapping("user/{id}/{username}/{password}")
    public AjaxData update(@Validated(value = {updateValidated.class}) User user, BindingResult errors) throws BindException {
        AjaxData ajaxData = new AjaxData();
        if (errors.hasErrors()){
            throw new BindException(errors);
        }
        userService.updateByPrimaryKeySelective(user);
        ajaxData.setDatas("更新成功");
        return ajaxData;
    }
}

注意:update方法需要传入主键id,否则无法更新

Service层

IUserService接口

import com.github.pagehelper.PageInfo;
import com.young.model.User;

public interface IUserService {

    PageInfo<User> selectAll(Integer PageNum, Integer PageSize);

    void deleteByPrimaryKey(Integer id);

    void insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    void updateByPrimaryKeySelective(User record);
}

UserService

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.young.mapper.UserMapper;
import com.young.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService implements IUserService {

    @Autowired
    private UserMapper userMapper;

    public UserService(){
        System.out.println("UserService run...");
    }

    @Override
    public PageInfo<User> selectAll(Integer pageNum, Integer pageSize) {
        if (pageNum==null){
            pageNum=1;
        }
        if (pageSize==null){
            pageSize=5;
        }
        PageHelper.startPage(pageNum,pageSize);
        List<User> list = userMapper.selectAll();
        PageInfo<User> userPageInfo = new PageInfo<>(list);
        return userPageInfo;
    }

    @Override
    public void deleteByPrimaryKey(Integer id) {
        int i = userMapper.deleteByPrimaryKey(id);
        if (i==0){
            throw new RuntimeException("id为"+id+"的用户不存在");
        }
    }

    @Override
    public void insertSelective(User record) {
        int i = userMapper.insertSelective(record);
        if (i==0){
            throw new RuntimeException("id为"+record.getId()+"的用户不存在");
        }
    }

    @Override
    public User selectByPrimaryKey(Integer id) {
        User user = userMapper.selectByPrimaryKey(id);
        if (user==null){
            throw new RuntimeException("id为"+id+"的用户不存在");
        }
        return user;
    }

    @Override
    public void updateByPrimaryKeySelective(User record) {
        int i = userMapper.updateByPrimaryKeySelective(record);
        if (i==0){
            throw new RuntimeException("id为"+record.getId()+"的用户不存在");
        }
    }
}

关于resource目录下文件不存在的问题

在某次运行过程中出现如下错误,即找不到springMVC.xml配置文件

IOException parsing XML document from class path resource [applicationContext.xml];nested exception is java.io.FileNotFoundException: class path resource [springMVC.xml] cannot be opened because it does not exist

首先可以确定该文件在resource目录下一定存在,我们可以先去排查web.xml文件下是否配置标签,如下:

<init-param>
  <param-name>contextConfigLocationparam-name>
  <param-value>classpath:springMVC.xmlparam-value>
init-param>

如果存在标签,或者之前可以运行突然出现该问题,我们应该检查target/classes目录下是否存在配置文件,如下图所示:
SMM整合_第3张图片
如果不存在说明maven打包出现了问题,可以尝试重新打包,如果不能解决,则需要在pom.xml文件中进行如下配置,目的是为了打包src/main/resources目录下的所有文件

<resources>
    <resource>
        <directory>src/main/javadirectory>
        <includes>
            <include>**/*.xmlinclude>
        includes>
    resource>
    <resource>
        <directory>src/main/resourcesdirectory>
        <includes>
            <include>**/*.xmlinclude>
        includes>
    resource>
    <resource>
        <directory>src/main/resourcesdirectory>
        <includes>
            <include>**/*.propertiesinclude>
        includes>
    resource>
resources>

如果对于之前的文件再次删除,但是日志显示该文件还存在,而且影响着程序的正常运行,也可以重新打包解决。

文档

使用swagger2生成文档,swagger2也可以用于测试

操作步骤

导入依赖



<dependency>
    <groupId>io.springfoxgroupId>
    <artifactId>springfox-swagger2artifactId>
    <version>2.9.2version>
dependency>

<dependency>
    <groupId>io.springfoxgroupId>
    <artifactId>springfox-swagger-uiartifactId>
    <version>2.9.2version>
dependency>

Swagger配置类

@Component
@Configuration
@EnableSwagger2
@EnableWebMvc
@ComponentScan("com.oracle.controller")
public class SwaggerConfig {
    @Bean
    public Docket createAPI() {
        return new Docket(DocumentationType.SWAGGER_2).forCodeGeneration(true).select().apis(RequestHandlerSelectors.any())
                //过滤生成链接
                .paths(PathSelectors.any()).build().apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        Contact contact = new Contact("xk", "http://www.oracle.com.cn", "[email protected]");
        ApiInfo apiInfo = new ApiInfoBuilder().license("Apache License Version 2.0").title("SSM整合接口文档").description("Swagger API Teste").contact(contact).version("1.0").build();
        return apiInfo;
    }

}

生成文档

在地址栏后输入swagger-ui.html即可进入文档在文档中可以查看控制器以及方法,也可以对方法进行测试。
SMM整合_第4张图片

一些注解

可以使用swagger提供的注解使文档的信息更加详细

@Api(description = "用户信息控制器")
public class UserController {
@ApiOperation(value ="根据id查询用户信息")
@GetMapping(value = "user/{id}")
public AjaxData selectById(@PathVariable("id") Integer id){
@ApiModel("用户实体类")
public class User implements Serializable {

    @ApiModelProperty(name = "用户编号")
    private Integer id;

SMM整合_第5张图片SMM整合_第6张图片

你可能感兴趣的:(SMM整合)