SSM增删改查操作(rest风格)
自己刚学完SSM来总结一下不用xml的整合过程
首先呢,要整合Spring 和 Mybatis 创建两个配置类(可以根据自己习惯起名) 代码如下
SpringConfig核心配置类(这里可以将Mybatis的配置类和Jdbc的配置类加载进来)
package com.itchj.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan({"com.itchj.service","com.itchj.dao"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybayisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
MybatisConfig配置类(在这里创建SqlSessionFactory工厂对象,并且映射mapper代理对象)
package com.itchj.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class MybayisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
//定义类型别名
factoryBean.setTypeAliasesPackage("com.itchj.domain");
return factoryBean;
}
//mapper代理对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itchj.dao");
return msc;
}
}
JdbcConfig配置类(提供数据源,这里使用Druid(德鲁伊)数据源,并且开启事物)
package com.itchj.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
//开启事物(在相应的业务层接口加上@Transactional)
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager ds = new DataSourceTransactionManager();
ds.setDataSource(dataSource);
return ds;
}
}
Spring整合Mybatis已经完成,下面是整合SpringMVC
首先写出SpringMvcConfig和ServletConfig两个配置类
SpringConfig
package com.itchj.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan({"com.itchj.controller","com.itchj.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
ServletConfig
package com.itchj.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//加入SpringConfig配置类
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//加入SpringMvcConfig配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
//配置SpringMvc的拦截路径
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
对静态资源放行以及拦截器配置可以单独写一个配置类继承WebMvcConfigurationSupport这个接口,也可以直接在SpringMvcConfig中实现WebMvcConfigurer这个接口来扩展功能(这里只说第一种,第二种和第一种重写的方法大同小异)
SpringMvcSupport
package com.itchj.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
到这里SSM整合算是差不多整完了就可以写代码了
dao层代码
package com.itchj.dao;
import com.itchj.domain.Book;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface BookDao {
@Insert("insert into tbl_book values(null, #{type}, #{name}, #{description})")
public int save(Book book);
@Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
public int update(Book book);
@Delete("delete from tbl_book where id = #{id}")
public int delete(Integer id);
@Select("select * from tbl_book where id = #{id}")
public Book gentById(Integer id);
@Select("select * from tbl_book")
public List<Book> getAll();
}
domain实体类(想用lombok可以直接导入坐标换,就不说了)
package com.itchj.domain;
public class Book {
private Integer id;
private String type;
private String name;
private String description;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", type='" + type + ''' +
", name='" + name + ''' +
", description='" + description + ''' +
'}';
}
}
service层接口和实现类代码
Service接口
package com.itchj.service;
import com.itchj.domain.Book;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Transactional
public interface BookService {
public boolean save(Book book);
public boolean update(Book book);
public boolean delete(Integer id);
public Book gentById(Integer id);
public List<Book> getAll();
}
Service实现类
package com.itchj.service.impl;
import com.itchj.controller.Code;
import com.itchj.dao.BookDao;
import com.itchj.domain.Book;
import com.itchj.exception.BusinessException;
import com.itchj.exception.SystemException;
import com.itchj.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
public boolean save(Book book) {
return bookDao.save(book) > 0 ;
}
@Override
public boolean update(Book book) {
return bookDao.update(book) > 0;
}
@Override
public boolean delete(Integer id) {
return bookDao.delete(id) > 0;
}
@Override
public Book gentById(Integer id) {
//以下几行做异常判断的
if (id == 1){
throw new BusinessException("请不要使用你的技术挑战我的耐性", Code.BUSINESS_ERR);
}
/* try {
int i = 1/0;
} catch (Exception e) {
throw new SystemException("服务器访问超时,请重试", e, Code.SYSTEM_TIMEOUT_ERR);
}*/
return bookDao.gentById(id);
}
@Override
public List<Book> getAll() {
return bookDao.getAll();
}
}
接下来就是表现层了
package com.itchj.controller;
import com.itchj.domain.Book;
import com.itchj.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result save(@RequestBody Book book) {
boolean flag = bookService.save(book);
return new Result(flag,flag ? Code.SAVE_OK:Code.SAVE_ERR);
}
@PutMapping
public Result update(@RequestBody Book book) {
boolean flag = bookService.update(book);
return new Result(flag,flag ? Code.UPDATE_OK:Code.UPDATE_ERR);
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
boolean flag = bookService.delete(id);
return new Result(flag,flag ? Code.DELETE_OK:Code.DELETE_ERR);
}
@GetMapping("/{id}")
public Result gentById(@PathVariable Integer id) {
Book book = bookService.gentById(id);
Integer code = book != null ? Code.GET_OK:Code.GET_ERR;
String msg = book != null ? "查询成功":"查询失败,请重新查询";
return new Result(book, code, msg);
}
@GetMapping
public Result getAll() {
List<Book> bookList = bookService.getAll();
Integer code = bookList != null ? Code.GET_OK:Code.DELETE_ERR;
String msg = bookList != null ? "查询成功":"查询失败,请重新查询";
return new Result(bookList, code, msg);
}
}
以上表现层代码用Result进行封装 向客服端发送json数据
Result代码
package com.itchj.controller;
public class Result {
private Object data;
private Integer code;
private String msg;
public Result() {
}
public Result(Object data, Integer code) {
this.data = data;
this.code = code;
}
public Result(Object data, Integer code, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
向客户端返回一些编码代表是否成功操作(可以单独创建一个类来进行编码设置)
package com.itchj.controller;
public class Code {
//代表操作成功
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
//代表操作失败
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
//代表异常类型
public static final Integer SYSTEM_TIMEOUT_ERR = 50001;
public static final Integer SYSTEM_ERR = 50002;
public static final Integer SYSTEM_UNKNOW_ERR = 59999;
public static final Integer BUSINESS_ERR = 60002;
}
然后还有很重要的异常处理(以上业务层有一些自定义异常进行实现)单独创建异常包分为系统异常和业务异常
SystemException
package com.itchj.exception;
public class SystemException extends RuntimeException{
//对异常进行编号 返回到前端
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public SystemException(String message, Integer code) {
super(message);
this.code = code;
}
public SystemException(String message, Throwable cause, Integer code) {
super(message, cause);
this.code = code;
}
}
RusinessException
package com.itchj.exception;
public class BusinessException extends RuntimeException{
//对异常进行编号 返回到前端
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(String message, Integer code) {
super(message);
this.code = code;
}
public BusinessException(String message, Throwable cause, Integer code) {
super(message, cause);
this.code = code;
}
}
对异常分好类之后加入异常处理器中
ProjectExceptionAdvice
package com.itchj.controller;
import com.itchj.exception.BusinessException;
import com.itchj.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice//异常处理器
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发消息给运维
//发消息给开发人员
return new Result(null,ex.getCode(),ex.getMessage());
}
//业务异常处理
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(null,ex.getCode(),ex.getMessage());
}
//其他异常处理
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
return new Result(null,Code.SYSTEM_UNKNOW_ERR,"系统繁忙,请稍后重试");
}
}
最后对上面SpringMvc中的拦截器进行补充(也可采用第二种直接在SpringMvcConfig中直接实现接口扩展功能)最后在SpringMvc中进行扫面加入拦截器
package com.itchj.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
//在目标方法执行之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
String param = request.getParameter("param");
if ("yes".equals(param)){
return true;
}else {
request.getRequestDispatcher("/error.jsp").forward(request, response);
return false;//返回true代表放行 返回false不放行
}
}
// 在目标方法执行之后视图返回之前
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
modelAndView.addObject("name","itheima");
}
//在整个流程都执行完毕后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}