![](https://img.haomeiwen.com/i21107801/4faafa41875d7119.png)
👉 在线笔记:https://du1in9.github.io/ssm_demo.github.io/
1 SSM 整合
1.1 整合配置
![](https://img.haomeiwen.com/i21107801/fb5764dcb1de9e8f.png)
-
Spring:Springconfig
@Configuration @ComponentScan({"com.itheima.service"}) @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MyBatisConfig.class}) @EnableTransactionManagement // 开启注解式事务驱动 public class SpringConfig { }
-
SpringMVC:Servletconfig、SpringMvcConfig
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); return new Filter[]{filter}; } }
@Configuration @ComponentScan("com.itheima.controller") @EnableWebMvc public class SpringMvcConfig { }
-
MyBatis:MybatisConfig、Jdbcconfig、jdbc.properties
public class MyBatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("com.itheima.domain"); return factoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.itheima.dao"); return msc; } }
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; } @Bean // 设置事务管理器 public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager ds = new DataSourceTransactionManager(); ds.setDataSource(dataSource); return ds; } }
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useSSL=false jdbc.username=root jdbc.password=123456
1.2 功能模块
-
表与实体类
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`(`id`, `type`, `name`, `description`) values (1, '计算机理论', 'Spring实战 第五版', 'Spring入门经典教程,深入理解Spring原理技术内幕'), (2, '计算机理论', 'Spring 5核心原理与30个类手写实践', '十年沉淀之作,手写Spring精华思想'), (3, '计算机理论', 'Spring 5设计模式', '深入Spring源码刨析Spring源码中蕴含的10大设计模式'), (4, '计算机理论', 'Spring MVC+Mybatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架'), (5, '计算机理论', '轻量级Java Web企业应用实战', '源码级刨析Spring框架,适合已掌握Java基础的读者'), (6, '计算机理论', 'Java核心技术 卷Ⅰ 基础知识(原书第11版)', 'Core Java第11版,Jolt大奖获奖作品'), (7, '计算机理论', '深入理解Java虚拟机', '5个纬度全面刨析JVM,大厂面试知识点全覆盖'), (8, '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉'), (9, '计算机理论', '零基础学Java(全彩版)', '零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想'), (10, '市场营销', '直播就这么做:主播高效沟通实战指南', '李子柒、李佳奇、薇娅成长为网红的秘密都在书中'), (11, '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍'), (12, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
@Data public class Book { private Integer id; private String type; private String name; private String description; }
-
dao(数据层):接口+自动代理
public interface BookDao { @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(业务层):接口+实现类
@Transactional // 添加 Spring 事务管理 public interface BookService { public boolean save(Book book); public boolean update(Book book); public boolean delete(Integer id); public Book getById(Integer id); public List<Book> getAll(); }
@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); return true; } public Book getById(Integer id) { return bookDao.getById(id); } public List<Book> getAll() { return bookDao.getAll(); } }
-
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(); } }
1.3 接口测试
-
service 接口测试(JUnit)
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class BookServiceTest { @Autowired private BookService bookService; @Test public void testDeleteById(){ System.out.println(bookService.delete(2)); } @Test public void testGetById(){ System.out.println(bookService.getById(1)); } @Test public void testGetAll(){ System.out.println(bookService.getAll()); } }
-
controller 接口测试(PostMan)
post: http://localhost:80/books {"type": "def", "name": "123", "description": "abc"} put: http://localhost:80/books {"id": "1", "type": "def", "name": "123", "description": "abc"} delete: http://localhost:80/books/2 get: http://localhost:80/books/3 get: http://localhost:80/books
2 统一结果封装
-
前端数据传输格式协议
-
表现层与协议实现
@Data public class Result { // 结果模型类 private Integer code; private Object data; private String msg; }
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; }
@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); } ... @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); } }
3 统一异常处理
3.1 异常处理器
-
出现异常现象的常见位置与常见诱因如下
-
框架内部地出的异常:因使用不合规导致
-
数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
-
业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等
-
表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
-
工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
-
-
异常处理器:集中的、统一的处理项目中出现的异常
package com.itheima.controller; @RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(Exception.class) public Result doException(Exception ex){ return new Result(666, null, "嘿嘿,异常你哪里跑!"); } }
3.2 项目异常处理
- 业务异常(BusinessException):规范 or 不规范的用户行为产生的异常
- 发送对应消息传递给用户,提醒规范操作
- 系统异常(SystemException):项目运行过程中可预计且无法避免的异常
- 发送固定消息传递给用户,安抚用户
- 发送特定消息给运维人员,提醒维护
- 记录日志
- 其他异常(Exception):编程人员未预期到的异常
- 发送固定消息传递给用户,安抚用户
- 发送特定消息给运维人员,提醒维护
- 记录日志
-
自定义异常编码
public class Code { public static final Integer SYSTEM_ERR = 50001; public static final Integer SYSTEM_TIMEOUT_ERR = 50002; public static final Integer SYSTEM_UNKNOW_ERR = 59999; public static final Integer BUSINESS_ERR = 60002; }
-
拦截并处理异常
package com.itheima.controller; @RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException ex){ return new Result(ex.getCode(), null, ex.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException ex){ return new Result(ex.getCode(), null, ex.getMessage()); } @ExceptionHandler(Exception.class) public Result doOtherException(Exception ex){ return new Result(Code.SYSTEM_UNKNOW_ERR, null, "系统繁忙,请稍后再试!"); } }
4 前后台协议联调
4.1 环境准备
-
将静态资源拷贝到 webapp 下,book.html 中的核心代码如下:
<body> <el-button @click="getAll()" class="dalfBut">查询</el-button> <el-button type="primary" class="butT" @click="handleCreate()">新建</el-button> <el-button @click="dialogFormVisible = false">取消</el-button> <el-button type="primary" @click="handleAdd()">确定</el-button> <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button> <el-button @click="dialogFormVisible4Edit = false">取消</el-button> <el-button type="primary" @click="handleEdit()">确定</el-button> <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button> </body>
<script> var vue = new Vue({ methods: { getAll() {}, // 1. 列表展示 resetForm() {}, // 重置表单 handleAdd () {}, // 2. 添加功能 handleCreate() {}, // 添加窗口 handleEdit() {}, // 3. 修改功能 handleUpdate(row) {}, // 编辑窗口 handleDelete(row) {} // 4. 删除功能 } }) </script>
-
因为 SpringMVC 会拦截,所以需要在 SpringConfig 的配置类中将其放行
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/js/**").addResourceLocations("/js/"); registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/"); } }
@Configuration @ComponentScan({"com.itheima.controller","com.itheima.config"}) @EnableWebMvc public class SpringMvcConfig { }
4.2 列表展示
-
页面的钩子函数
created()
调用了this.getAll()
方法,使用 axios 发送异步请求从后台获取数据getAll() { axios.get("/books").then((res)=>{ this.dataList = res.data.data; }); }
4.3 添加功能
-
页面的新建按钮绑定了
@click="handleCreate()"
方法,在方法中打开新增面板handleCreate() { this.dialogFormVisible = true; this.resetForm(); }, resetForm(){ this.formData = {}; }
确定按钮绑定了
@click="handleAdd()"
方法,在方法中发送请求和数据,响应成功后将新增面板关闭并重新查询数据handleAdd () { axios.post("/books",this.formData).then((res)=>{ if(res.data.code == 20011){ // 如果操作成功,关闭弹层,显示数据 this.dialogFormVisible = false; this.$message.success("添加成功"); }else if(res.data.code == 20010){ // 如果操作失败,提示错误信息 this.$message.error("添加失败"); }else{ this.$message.error(res.data.msg); } }).finally(()=>{ this.getAll(); }); }
-
后台返回操作结果,将 Dao 层的增删改方法返回值从 void 改成 int
@Insert("insert into tbl_book (type,name,description) values(#{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);
在 BookServiceImpl 中,增删改方法根据 Dao 的返回值来决定返回 true/false
public boolean save(Book book) { return bookDao.save(book) > 0; } public boolean update(Book book) { return bookDao.update(book) > 0; } public boolean delete(Integer id) { return bookDao.delete(id) > 0; }
4.4 编辑功能
-
页面中的编辑按钮绑定了
@click="handleUpdate(scope.row)"
,在方法中根据 ID 查询图书信息handleUpdate(row) { axios.get("/books/"+row.id).then((res)=>{ if(res.data.code == 20041){ // 如果查询成功, 打开修改面板回显数据 this.formData = res.data.data; this.dialogFormVisible4Edit = true; }else{ // 如果查询失败, 提示错误信息 this.$message.error(res.data.msg); } }); }
-
在
handleEdit
方法中发送异步请求提交修改数据handleEdit() { axios.put("/books",this.formData).then((res)=>{ if(res.data.code == 20031){ // 如果操作成功,关闭弹层,显示数据 this.dialogFormVisible4Edit = false; this.$message.success("修改成功"); }else if(res.data.code == 20030){ // 如果操作失败,提示错误信息 this.$message.error("修改失败"); }else{ this.$message.error(res.data.msg); } }).finally(()=>{ this.getAll(); }); }
4.5 删除功能
handleDelete(row) {
this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
type:'info'
}).then(()=>{ // 用户点击确定,发送异步请求, 并携带需要删除数据的主键ID
axios.delete("/books/"+row.id).then((res)=>{
if(res.data.code == 20021){
this.$message.success("删除成功");
}else{
this.$message.error("删除失败");
}
}).finally(()=>{
this.getAll();
});
}).catch(()=>{ // 用户点击取消,提示操作已经被取消
this.$message.info("取消删除操作");
});
}
5 基于 SpringBoot 整合
需求:根据之前的 Spring 案例,实现基于 SpringBoot 的 SSM 整合
-
config 类:全部删除
-
dao 类:设置
@Mapper
-
test 类:设置
@SpringBootTest
-
pom.xml:配置必要的资源坐标
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency>
-
application.yml:配置数据源、端口等
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db username: root password: 123456
-
static:静态资源,index.html 设置主页
<script> document.location.href="pages/books.html”; </script>
网友评论