创建工程
SSM整合
Spring
SpringConfig
@Configuration
@ComponentScan({"com.ityc.service"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
//事物
@EnableTransactionManagement
public class SpringConfig {
}
MyBatis
MyBatisConfig
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("com.ityc.domain");
return factoryBean;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc= new MapperScannerConfigurer();
msc.setBasePackage("com.ityc.dao");
return msc;
}
}
JdbcConfig
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.passworld}")
private String passworld;
//导入MySQL
@Bean
public DataSource DataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(passworld);
return dataSource;
}
//事物
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager ds = new DataSourceTransactionManager();
ds.setDataSource(dataSource);
return ds;
}
}
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useSSL=false
jdbc.username=root
jdbc.passworld=lyc
SpringMVC
SpringMvcConfig
@Configuration
@ComponentScan("com.ityc.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
功能模块
表与实体类
package com.ityc.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 + '\'' +
'}';
}
}
DROP TABLE IF EXISTS `tbl_book`;
CREATE TABLE `tbl_book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `tbl_book` VALUES (1, '计算机理论', 'Spring实战 第5版', 'Spring入门经典教程,深入理解Spring原理技术内幕');
INSERT INTO `tbl_book` VALUES (2, '计算机理论', 'Spring 5核心原理与30个类手写实战', '十年沉淀之作,手写Spring精华思想');
INSERT INTO `tbl_book` VALUES (3, '计算机理论', 'Spring 5 设计模式', '深入Spring源码剖析Spring源码中蕴含的10大设计模式');
INSERT INTO `tbl_book` VALUES (4, '计算机理论', 'Spring MVC+MyBatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手');
INSERT INTO `tbl_book` VALUES (5, '计算机理论', '轻量级Java Web企业应用实战', '源码级剖析Spring框架,适合已掌握Java基础的读者');
INSERT INTO `tbl_book` VALUES (6, '计算机理论', 'Java核心技术 卷I 基础知识(原书第11版)', 'Core Java 第11版,Jolt大奖获奖作品,针对Java SE9、10、11全面更新');
INSERT INTO `tbl_book` VALUES (7, '计算机理论', '深入理解Java虚拟机', '5个维度全面剖析JVM,大厂面试知识点全覆盖');
INSERT INTO `tbl_book` VALUES (8, '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉');
INSERT INTO `tbl_book` VALUES (9, '计算机理论', '零基础学Java(全彩版)', '零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想和核心技术');
INSERT INTO `tbl_book` VALUES (10, '市场营销', '直播就该这么做:主播高效沟通实战指南', '李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO `tbl_book` VALUES (11, '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍');
INSERT INTO `tbl_book` VALUES (12, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
dao(接口+自动代理)
package com.ityc.dao;
import com.ityc.domain.Book;
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 org.springframework.web.servlet.config.annotation.EnableWebMvc;
import java.util.List;
public interface BookDao {
//@Insert("insert into tbl_book values (null,#{type},#{name},#{description})")
@Insert("insert into tbl_book (type,name,description) values (#{type},#{name},#{description})")
public void save(Book book);
@Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id=#{id}")
public void update(Book book);
@Delete("delete from tbl_book where id = #{id}")
public void delete(Integer id);
@Select("select * from tbl_book where id = #{id}")
public Book getById (Integer id);
@Select("select * from tbl_book")
public List<Book> getALL();
}
service(接口+实体类)
//接口
package com.ityc.service;
import com.ityc.domain.Book;
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 org.springframework.transaction.annotation.Transactional;
import java.util.List;
//开启事物
@Transactional
public interface BookService {
/**
* 保存
* @param book
* @return
*/
public boolean save(Book book);
/**
* 修改
* @param book
* @return
*/
public boolean update(Book book);
/**
* 删除 根据id
* @param id
* @return
*/
public boolean delete(Integer id);
/**
* 按id查询
* @param id
* @return
*/
public Book getById (Integer id);
/**
* 查询全部
* @return
*/
public List<Book> getALL();
}
//实现类
package com.ityc.service.impl;
import com.ityc.dao.BookDao;
import com.ityc.domain.Book;
import com.ityc.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;
public boolean save(Book book) {
bookDao.save(book);
return true;
}
public boolean update(Book book) {
bookDao.update(book);
return true;
}
public boolean delete(Integer id) {
bookDao.delete(id);
if(bookDao.getById(id)!=null){
bookDao.delete(id);
return true;
}else{
return false;
}
}
public Book getById(Integer id) {
return bookDao.getById(id);
}
public List<Book> getALL() {
return bookDao.getALL();
}
}
//测试
package com.ityc.service;
import com.ityc.config.SpringConfig;
import com.ityc.domain.Book;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {
@Autowired
private BookService bookService;
@Test
public void testGetById(){
Book book = bookService.getById(1);
System.out.println(book);
}
@Test
public void testGetAll(){
List<Book> bookAll = bookService.getALL();
System.out.println(bookAll);
}
}
conroller
表现层接口测试(PostMan)
package com.ityc.controller;
import com.ityc.domain.Book;
import com.ityc.service.BookService;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
//基于Restful的controller开发
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public boolean save(@RequestBody Book book) {
return bookService.save(book);
}
@PutMapping
public boolean update(@RequestBody Book book) {
return bookService.update(book);
}
@DeleteMapping({"/{id}"})
public boolean delete(@PathVariable Integer id) {
return bookService.delete(id);
}
@GetMapping({"/{id}"})
public Book getById(@PathVariable Integer id) {
return bookService.getById(id);
}
@GetMapping
public List<Book> getALL() {
return bookService.getALL();
}
}
web配置类
package com.ityc.config;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
import javax.servlet.Filter;
public class SelectConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//根配置
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
//专门应对web请求的处理
//这里创建的容器对象与上方的容器对象不是同一个
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
//POST提交乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
//Result类中的字段不是固定的,可以根据需要自行增减
//提供若干个构造方法,方便操作
package com.ityc.controller;
public class Result {
private Object data;
private Integer code;
private String msg;
public Result() {
}
public Result( Integer code,Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Result( Integer code,Object data) {
this.data = data;
this.code = code;
}
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.ityc.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;
}
package com.ityc.controller;
import com.ityc.domain.Book;
import com.ityc.service.BookService;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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?Code.SAVE_OK:Code.SAVE_ERR,flag);
}
@PutMapping
public Result update(@RequestBody Book book) {
boolean flag = bookService.update(book);
return new Result(flag?Code.UPDATE_OK:Code.UPDATE_ERR,flag);
}
@DeleteMapping({"/{id}"})
public Result delete(@PathVariable Integer id) {
boolean flag = bookService.delete(id);
String msg= flag?"删除成功":"数据为空,删除失败";
return new Result(flag?Code.DELETE_OK:Code.DELETE_ERR,flag,msg);
}
@GetMapping({"/{id}"})
public Result getById(@PathVariable Integer id) {
Book book = bookService.getById(id);
Integer code = book!= null ? Code.GET_OK:Code.GET_ERR;
String msg= book != null?"查询成功":"数据为空,查询失败";
return new Result(code,book,msg);
}
@GetMapping
public Result getALL() {
List<Book> bookList = bookService.getALL();
Integer code = bookList!= null ? Code.GET_OK:Code.GET_ERR;
String msg= bookList != null?"查询成功":"数据为空,查询失败";
return new Result(code,bookList,msg);
}
}
注:
表现层数据封装,通过Result与Code类配合业业务,将数据整理成统一格式,反馈给前端页面,再由前端页面的书写人员进行统一解析。
出现异常现象的常见位置与常见诱因如下
思考:各个层级均出现异常,异常处理代码书写在哪一层?
所有的异常均抛出到表现层进行处理
表现层处理异常,每个方法中单独书写,代码书写量巨大,且意义不强,如何解决?——AOP思想
SpringMVC为我们提供了异常处理器,来为我们集中的,统一的处理项目中的异常。
package com.ityc.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//Rest风格开发的控制器类做增强,本注解自带@ResponseBody注解与@Component注解,具备对应的功能
@RestControllerAdvice
public class ProjectExceptionAdvice {
//写一个方法用于处理异常
//设置拦截处理的异常类型
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
System.out.println("异常出来吧,别藏了");
return new Result(666,null,"异常出现了");
}
}
业务异常(BusinessException)
不规范用户行为操作产生的异常
规范的用户行为产生的异常
系统异常(SystemException)
其他异常(Exception)
自定义项目系统级异常
package com.ityc.exception;
public class SystemException extends RuntimeException{
private Integer code;
public SystemException( Integer code,String message) {
super(message);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
-
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
自定义项目业务级异常
package com.ityc.exception;
public class BusinessException extends RuntimeException {
private Integer code;
public BusinessException( Integer code,String message) {
super(message);
this.code = code;
}
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
自定义异常编码(可持续补充)
package com.ityc.controller;
public class Code {
public static final Integer SYSTEM_ERR = 50001;
public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
public static final Integer BUSINESS_ERR = 50003;
public static final Integer SYSTEM_UNKNOW_ERR = 59999;
}
触发自定义异常
public Book getById(Integer id) {
if (id < 1){
throw new BusinessException(Code.BUSINESS_ERR,"警告,非法操作");
}
return bookDao.getById(id);
}
拦截并处理异常
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException sex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,sex对象发给开发人员
return new Result(sex.getCode(),null,sex.getMessage());
}
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException bex){
//记录日志
//发送消息给运维
//发送邮件给开发人员
return new Result(bex.getCode(),null,bex.getMessage());
}
//写一个方法用于处理异常
//设置拦截异常类型
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,sex对象发给开发人员
System.out.println("异常出来吧,别藏了");
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"出现了位置异常,系统繁忙请稍后再试");
}
}
异常处理器效果
注: