SSM整合之纯注解方式,注解实现事务,异常,与拦截器

29 篇文章 0 订阅

SSM整合之纯注解方式Spring,SpringMVC,Mybatis

使用纯注解的方式,整合ssm,

sql语句与数据表

在上一篇SSM整合之XML方式中有,

创建maven项目(代码中注释为详细解释)

删除web.xml文件
在这里插入图片描述

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.93.132:3306/test
jdbc.username=root
jdbc.password=root

配置类

ServletContainersInitConfig类替换web.xml
package com.fs.springssm.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

    //创建Servlet容器时,使用注解的方式加载SPRINGMVC配置类中的信息,并加载成WEB专用的ApplicationContext对象
    //该对象放入了ServletContext范围,后期在整个WEB容器中可以随时获取调用
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMVCConfig.class);
        return ctx;
    }

    //注解配置映射地址方式,服务于SpringMVC的核心控制器DispatcherServlet
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    //基本等同于<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        //读取主配置类
        ctx.register(SpringConfig.class);
        return ctx;
    }

    //乱码处理作为过滤器,在servlet容器启动时进行配置,相关内容参看Servlet零配置相关课程
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        //触发父类的onStartup
        super.onStartup(servletContext);
        //1.创建字符集过滤器对象
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        //2.设置使用的字符集
        cef.setEncoding("UTF-8");
        //3.添加到容器(它不是ioc容器,而是ServletContainer)
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", cef);
        //4.添加映射
        registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/*");
    }
}
SpringMVCConfig替换spring-mvc.xml
package com.fs.springssm.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import javax.sql.DataSource;

//等同于<context:component-scan base-package="com.fs.springssm.controller"/>
@ComponentScan(value = "com.fs.springssm.controller")
//开启SpringMVC的注解解析,等同于<mvc:annotation-driven/>,还不完全相同,
@EnableWebMvc
//配置声明式事务
// <tx:annotation-driven transaction-manager="transactionManager"/> bean的名称默认取transactionManager
@EnableTransactionManagement
//导入拦截器配置类
@Import({WebConfigInterceptor.class})
public class SpringMVCConfig {

    /*

<!-- 注意:   开启事务驱动注解的支持,配合@Transactional使用-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        注入连接池-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
     */
    //等同于<bean id="txManager"/>
    @Bean("transactionManager")
    //等同于<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    public DataSourceTransactionManager getTxManager(@Autowired DataSource dataSource){
        DataSourceTransactionManager tm = new DataSourceTransactionManager();
        //等同于<property name="dataSource" ref="dataSource"/>
        tm.setDataSource(dataSource);
        return tm;
    }

    /*

    <!--        配置视图解析器,方便访问jsp页面,并交给spring管理-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--       视图解析前缀(访问前缀)-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--       视图解析后缀(访问后缀)-->
        <property name="suffix" value=".jsp"/>
    </bean>
     */
    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver(){
        InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
        internalResourceViewResolver.setPrefix("/WEB-INF/pages/");
        internalResourceViewResolver.setSuffix(".jsp");
        return internalResourceViewResolver;
    }
}

整合MyBatis,创建两个配置类来替换springMybatis.xml
jdbcConfig
package com.fs.springssm.config;


import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

//等同于<context:property-placeholder location="classpath*:jdbc.properties"/>
@PropertySource(value = "classpath:jdbc.properties")
public class JdbcConfig {
    //使用注入的形式,读取properties文件中的属性值,等同于<property name="*******" value="${jdbc.driver}"/>
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;


    //将druid连接池对象交给springIOC管理
    /*
    等同于
    <!--    配置德鲁伊连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
     */
    @Bean
    public DataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(userName);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
}

MybatisConfig
package com.fs.springssm.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;
/*
Mybatis的配置类
 */
public class MybatisConfig {

    /*
    <!--    配置SqlSessionFactoryBean-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
<!--       给实体类起别名,方便MyBatis映射 -->
        <property name="typeAliasesPackage" value="com.fs.springssm.pojo"/>
    </bean>
     */
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage("com.fs.springssm.pojo");
        return sqlSessionFactoryBean;
    }

    /*
    <!--    配置映射扫描dao接口的包,由MyBatis动态代理生成实现类交给spring管理-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.fs.springssm.dao"/>
    </bean>
     */
    @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.fs.springssm.dao");
        return mapperScannerConfigurer;
    }

}

SpringConfig来替换applicationContex.xml
package com.fs.springssm.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
//扫描路径下的bean,
@ComponentScan("com.fs.springssm")
//导入其他配置文件
@Import({JdbcConfig.class,MybatisConfig.class,SpringMVCConfig.class})
public class SpringConfig {
}

创建一个拦截器类来配置拦截参数(实现WebMvcConfigurer接口,重写addInterceptors()方法)
package com.fs.springssm.config;

import com.fs.springssm.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

//继承WebMvcConfigurerAdapter(已过时)重写addInterceptors()
//public class WebConfigInterceptor extends WebMvcConfigurerAdapter {
//点击WebConfigInterceptor看源码得,他是实现的WebMvcConfigurer接口
//那就实现WebMvcConfigurer接口,重写addInterceptors()方法
public class WebConfigInterceptor implements WebMvcConfigurer {
    /*
    <!--    配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
<!--            拦截controller的所有请求-->
            <mvc:mapping path="/**"/>
<!--            登录页面不拦截-->
            <mvc:exclude-mapping path="/login"/>
<!--            配置自定义的拦截器-->
            <bean class="com.fs.springssm.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
     */

    //注入自定义拦截器
    @Autowired
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置自定义拦截器
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(myInterceptor);
        //拦截SpringMVC的所有请求
        interceptorRegistration.addPathPatterns("/**");
        //排除拦截login,不拦截login
        interceptorRegistration.excludePathPatterns("/login");
    }
}

自定义异常类与拦截器类

MyInterceptor自定义拦截器类
package com.fs.springssm.interceptor;
/*
拦截器与过滤器有什么不同
    Interceptor拦截器是SpringMVC的技术,拦截控制的controller,拦截springIOC中的controller
    filter过滤器是tomcat中所有的接收到的请求都可以被拦截,包括spring中的controller

    //三个方法的运行顺序为    preHandle -> controller中被拦截的方法执行 ->postHandle -> afterCompletion
    //如果preHandle返回值为false,三个方法仅运行preHandle

    由HandlerInterceptor接口源码得知,方法被default修饰了(java8新特性)被默认实现了方法的,所以我们自定义拦截器没有强制我们重写接口中的方法
    所以我们需要自己重写接口中的方法实现自定义拦截器的具体功能

    HandlerInterceptor接口源码
    public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}
 */
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

//自定义拦截器需要实现HandleInterceptor接口,实现这个接口没有被强制现实所有方法
//是因为HandlerInterceptor接口中的方法有默认的default实现方法,所以我们需要自己重写接口中的方法
@Component
public class MyInterceptor implements HandlerInterceptor {
    //处理器运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request,//请求携带的request
                             HttpServletResponse response,//响应携带的Response
                             //handler就是我们执行的controller方法路径
                             Object handler) throws Exception {
        //下面打印的就是我们自己写的controller的方法,使用反射技术
        //public java.lang.String com.fs.springmvc.controller.InterceptorController.handleRun()
        ///System.out.println(handler.toString());
        System.out.println("前置运行----a1");
        //返回值为false将拦截原始处理器的运行,访问的controller中的方法不会被执行,
        //而且后面的postHandle,afterCompletion也不会执行
        //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
        return true;
    }

    //处理器运行之后执行
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           //controller执行方法后要返回的视图ModelAndView
                           ModelAndView modelAndView) throws Exception {
        System.out.println("后置运行----b1");
    }

    //所有拦截器的后置执行全部结束后,执行该操作
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                //
                                Exception ex) throws Exception {
        System.out.println("完成运行----c1");
    }

    //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
    //如果preHandle返回值为false,三个方法仅运行preHandle
}

ExceptionAdvice自定义异常通知类
package com.fs.springssm.exception;

import com.fs.springssm.result.Code;
import com.fs.springssm.result.ResultMapper;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


@ControllerAdvice//表示为异常通知类,会对ioc中的所以类的异常进行统一管理
public class ExceptionAdvice {

    //异常处理方法,处理个大的,也可以细分
    @ExceptionHandler(Exception.class)
    @ResponseBody//将自定义的结果映射类返回给前端
    public ResultMapper exceptionHandle(Exception ex){
        //创建自定义的结果集,封装成json返回给前端
        ResultMapper<String> exceptionResultMapper = new ResultMapper<>();
        exceptionResultMapper.setCode(Code.DELETE_ERROR);
        exceptionResultMapper.setData("服务器发生异常啦");
        exceptionResultMapper.setMessage("服务器繁忙,请稍候再试~~~");
        exceptionResultMapper.setFlag(false);
        return exceptionResultMapper;
    }
}

pojo实体类

Account
package com.fs.springssm.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Account {
    private Integer id;
    private String name;
    private Double money;
}

dao

AccountDao
package com.fs.springssm.dao;

import com.fs.springssm.pojo.Account;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

public interface AccountDao {
    //增
    @Insert("INSERT INTO account(NAME,money) VALUE(#{name},#{money})")
    int addAccount(Account account);
    //删
    @Delete("DELETE FROM account WHERE id = #{id}")
    int delAccountById(Integer id);
    //改
    @Update("UPDATE account SET money = #{money} WHERE id = #{id}")
    int updateAccount(Account account);
    //查询所有
    @Select("select * from account")
    List<Account> findAccountAll();
    //根据id查询
    @Select("select * from account where id = #{id}")
    Account findAccountById(Integer id);
    //根据名字查询
    @Select("select * from account where name = #{name}")
    Account findAccountByName(String name);
}

service

AccountService
package com.fs.springssm.service;

import com.fs.springssm.pojo.Account;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;


public interface AccountService {
    //增
    int addAccount(Account account);
    //删
    int delAccountById(Integer id);
    //改
    int updateAccount(Account account);
    //查询所有
    List<Account> findAccountAll();
    //根据id查询
    Account findAccountById(Integer id);

    //对转账业务进行事务管理
    //转账业务
    @Transactional
    Boolean transferMoney(String nameA,String nameB,double money);
}

AccountServiceImpl
package com.fs.springssm.service.impl;

import com.fs.springssm.dao.AccountDao;
import com.fs.springssm.pojo.Account;
import com.fs.springssm.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AccountServiceImpl implements AccountService {

    //依耐dao层
    @Autowired
    private AccountDao accountDao;

    @Override
    public int addAccount(Account account) {
        return accountDao.addAccount(account);
    }

    @Override
    public int delAccountById(Integer id) {
        return accountDao.delAccountById(id);
    }

    @Override
    public int updateAccount(Account account) {
        return accountDao.updateAccount(account);
    }

    @Override
    public List<Account> findAccountAll() {
        return accountDao.findAccountAll();
    }

    @Override
    public Account findAccountById(Integer id) {
        return accountDao.findAccountById(id);
    }

    //转账业务
    @Override
    public Boolean transferMoney(String nameA, String nameB, double money) {
        //先把两个用户信息查出来
        Account name1 = accountDao.findAccountByName(nameA);
        Account name2 = accountDao.findAccountByName(nameB);
        //将1-money 2+money
        name1.setMoney(name1.getMoney() - money);
        name2.setMoney(name2.getMoney() + money);

        //然后更新两个用户
        int a = accountDao.updateAccount(name1);
        //制作异常
//        int i = 1 / 0;
        int b = accountDao.updateAccount(name2);
        //没有异常就返回true
        return a == b && b > 0;
    }
}

对响应的结果进行封装result

ResultMapper
package com.fs.springssm.result;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultMapper<T> {
    //响应回前端状态码
    private Integer code;
    //是否成功
    private Boolean flag;
    //数据
    private T data;
    //消息
    private String message;


    public ResultMapper(Boolean flag, String message) {
        this.flag = flag;
        this.message = message;
        this.code = Code.DELETE_OK;
        this.data = null;
    }
}

Code
package com.fs.springssm.result;

public class Code {
//    操作结果编码
    public static final Integer SAVE_OK = 20011;
    public static final Integer UPDATE_OK = 20021;
    public static final Integer DELETE_OK = 20031;
    public static final Integer GET_OK = 20041;

    public static final Integer SAVE_ERROR = 20010;
    public static final Integer UPDATE_ERROR = 20020;
    public static final Integer DELETE_ERROR = 20030;
    public static final Integer GET_ERROR = 20040;

//    系统错误编码

//    操作权限编码

//    校验结果编码

}

controller

AccountController
package com.fs.springssm.controller;


import com.fs.springssm.pojo.Account;
import com.fs.springssm.result.Code;
import com.fs.springssm.result.ResultMapper;
import com.fs.springssm.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequestMapping("/account")
@RestController//@Controller@ResponseBody相当于这两个注解
public class AccountController {

    @Autowired
    private AccountService accountService;

    //添加
    @RequestMapping("/add")
    @ResponseBody
    public ResultMapper<String> addAccount(@RequestBody Account account){
        int i = accountService.addAccount(account);
        if (i>0) {
            return new ResultMapper<>(Code.DELETE_OK,true,"添加成功","成功");
        }else {
            return new ResultMapper<>(Code.GET_ERROR,false,"添加失败","失败");
        }
    }

    //查询所有
    @RequestMapping("/all")
    @ResponseBody
    public ResultMapper<List<Account>>  findAll(){
        List<Account> accountAll = accountService.findAccountAll();
        if (accountAll.size()!=0) {
            return new ResultMapper<>(Code.DELETE_OK,true,accountAll,"查询成功");
        }else {
            return new ResultMapper<>(Code.GET_ERROR,false,null,"查询结果为空");
        }
    }


    //转账
    @RequestMapping("/transfer")
    @ResponseBody
    public ResultMapper transferMoney(String nameA,String nameB,Double money){
        //调用转账方法
        Boolean aBoolean = accountService.transferMoney(nameA, nameB, money);
        //将结果封装到结果对象中
        ResultMapper resultMapper = new ResultMapper<>(aBoolean,"转账结果");
        return resultMapper;
    }

}

启动tomcat测试

运行测试在上一篇ssm整合之XML方式中有,运行结果一模一样.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值