小白SSM整合小案例-后端代码(欢迎观看,jym)

144 阅读6分钟

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...");
    }
}

最后附上包结构图(这里建议将拦截器直接加在controller下的interceptor包中,就可以在SpringMvcConfig中只扫描com.itchj.controller了

jiegou.png