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方式中有,运行结果一模一样.