SSM整合Springboot

1.0 概述

1.1 持久层:

DAO层(mapper)

  • DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此

    • DAO层的设计首先是设计DAO的接口,

    • 然后在spring-mapper.xml的配置文件中定义此接口的实现类,

    • 然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,

    • DAO层的数据源配置,以及有关数据库连接的参数都在spring-mapper的配置文件中进行配置。

1.2 业务层:

Service层

  • Service层:Service层主要负责业务模块的逻辑应用设计。

    • 首先设计接口,再设计其实现的类

    • 接着再在Spring的配置文件中配置其实现的关联。这样我们就可以在应用中调用Service接口来进行业务处理

    • Service层的业务实现,具体要调用到已定义的DAO层的接口

    • 数据库的事务配置在service.xml中配置

    • 封装Service层的业务逻辑有利于通用的业务逻辑的独立性和重复利用性,程序显得非常简洁。

1.3 表现层:

Controller层(Handler层)

  • Controller层:Controller层负责具体的业务模块流程的控制,

    • 在此层里面要调用Service层的接口来控制业务流程,

    • 控制的配置也同样是在springmvc.xml的配置文件里面进行,针对具体的业务流程,会有不同的控制器,

    • 我们具体的设计过程中可以将流程进行抽象归纳,设计出可以重复利用的子单元流程模块,

      这样不仅使程序结构变得清晰,也大大减少了代码量

1.4 View层
  • View层 此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示.

1.5 各层联系
  • DAO层,Service层这两个层次都可以单独开发,互相的耦合度很低,完全可以独立进行,这样的一种模式在开发大项目的过程中尤其有优势

  • Controller,View层因为耦合度比较高,因而要结合在一起开发,但是也可以看作一个整体独立于前两个层进行开发。这样,在层与层之前我们只需要知道接口的定义,调用接口即可完成所需要的逻辑单元应用,一切显得非常清晰简单。

  • Service逻辑层设计

    • Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。

2.0 SSM整合

2.1 创建SpringBoot项目

image-20230309210725476

2.2 引入依赖
 <properties><java.version>11</java.version><mybatis.version>2.2.2</mybatis.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

注意:引入 spring-boot-devtools 依赖后,每次我们只需要重新编译源代码即可,不要需要重启springboot项目

2.3 工程搭建
#启动端口
server.port=8088
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql:///
spring.datasource.username=
spring.datasource.password=
# 日志登记
logging.level.com.codingfuture.mybatis_demo = debug
#xml配置
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
#驼峰映射
mybatis.configuration.map-underscore-to-camel-case=true
#配置别名
mybatis.type-aliases-package = com.codingfuture.mybatis_demo.entity 
#主键返回
mybatis.configuration.use-generated-keys=true
# 延迟加载
mybatis.configuration.lazy-loading-enabled=true
#二级缓存
mybatis.configuration.cache-enabled=true
2.4 包目录

image-20230309211610595

2.5 封装Result工具类
package com.codingfuture.ssm_test.util;
import lombok.Getter;
@Getter
public class Result {private int code;private String message;private Object data;private Result() {}public static Result ok () {Result result = new Result();result.code = 200;result.message = "success";return result;}public static Result ok (Object data) {Result result = new Result();result.code = 200;result.message = "success";result.data = data;return  result;}public static Result error (int code,String message) {Result result = new Result();result.code = code;result.message = message;return  result;}
}// 测试
@RestController
public class PersonController {@Autowiredprivate PersonService personService;@GetMapping("/findList")public Result findList () {List<Person> list = personService.findList();return  list.size()!= 0 ?Result.ok(list) :Result.error(201,"无数据");}
}
2.6 优化工具类
@Getter
public class Result<T> {private int code;private String message;private T data;private static final int DEFAULT_SUCCESS_CODE = 200;private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";private Result() {}public static Result<Void> ok () {Result<Void> result = new Result<>();result.code = DEFAULT_SUCCESS_CODE;result.message = DEFAULT_SUCCESS_MESSAGE;return result;}public static  <T> Result<T> ok (T data) {Result<T> result = new Result<>();result.code = DEFAULT_SUCCESS_CODE;result.message = DEFAULT_SUCCESS_MESSAGE;result.data = data;return result;}public static Result<Void> error (int code,String message) {Result<Void> result = new Result<>();result.code = code;result.message = message;return result;}}

3.0 分页

3.1 基本使用
@RestController
public class SpAttributeController {@Autowiredprivate SpAttributeService spAttributeService;@GetMapping("/find")public Result<List<SpAttribute>> findByPage() {return Result.ok(spAttributeService.findByPage());}
}
public interface SpAttributeService {List<SpAttribute> findByPage();
}
@Service
public class SpAttributeServiceImpl implements SpAttributeService {@Autowiredprivate SpAttributeMapper spAttributeMapper;@Overridepublic List<SpAttribute> findByPage() {return spAttributeMapper.findByPage();}
}
@Mapper
public interface SpAttributeMapper {@Select(" select * from sp_attribute")List<SpAttribute> findByPage();
}
@Data
public class SpAttribute {private Integer attrId;private String attrName;private Integer catId;private String attrSel;private String attrWrite;private String attrVals;// getter&&setter
}
3.2 导入依赖
<pagehelper-version>1.4.1</pagehelper-version>
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>${pagehelper-version}</version>
</dependency>
3.3 分页助手

Page<SpAttribute> page1 = PageHelper.offsetPage(pageNum, pageSize);
  Page<SpAttribute> page2 = PageHelper.startPage(pageNum, pageSize);

3.4 测试:
//  http://localhost:8088/findByPage1?pageNum=1&pageSize=10@GetMapping("/findByPage1")public Result<List<SpAttribute>> findByPage1(Integer pageNum, Integer pageSize) {
//      PageHelper.offsetPage(pageNum, pageSize);PageHelper.startPage(pageNum, pageSize);return Result.ok(spAttributeService.findByPage());}
3.5 封装PageData
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageData<T> {private List<T> data;private long total;
}
3.6 测试
@GetMapping("/findByPage2")public Result<PageData<SpAttribute>> findByPage2(Integer pageNum, Integer pageSize) {Page<SpAttribute> result = PageHelper.startPage(pageNum, pageSize);spAttributeService.findByPage();PageData<SpAttribute> pageData = new PageData<>(result.getResult(), result.getTotal());return Result.ok(pageData);}
3.7 分页演示
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>table 模块快速使用</title><!-- 引入 layui.css --><link rel="stylesheet" href="//unpkg.com/layui@2.6.8/dist/css/layui.css"><!-- 引入 layui.js --><script src="//unpkg.com/layui@2.6.8/dist/layui.js"></script>
</head>
<body>
<table id="demo" lay-filter="test"></table><script>layui.use('table', function () {var table = layui.table;//第一个实例table.render({elem: '#demo', height: 312, url: '/findByPage3' //数据接口, page: true //开启分页, cols: [[ //表头{field: 'attrId', title: '主键id', width: 180, sort: true, fixed: 'left'}, {field: 'attrName', title: '属性名称', width: 180}, {field: 'catId', title: '类型id', width: 180, sort: true}, {field: 'attrSel', title: '动态参数', width: 180}, {field: 'attrWrite', title: '静态属性', width: 180}]],parseData: function(d){return {code: d.code,msg: d.message,count: d.data.total,data: d.data.data,};}});});
</script>
</body>
</html>
@GetMapping("/findByPage3")public Result<PageData<SpAttribute>> findByPage3(@RequestParam(name = "page")Integer pageNum,@RequestParam(name = "limit")Integer pageSize) {Page<SpAttribute> result = PageHelper.startPage(pageNum, pageSize);spAttributeService.findByPage();PageData<SpAttribute> pageData = new PageData<>(result.getResult(), result.getTotal());return Result.ok(pageData);}
3.8 增加排序功能

 Page<SpAttribute> result = PageHelper.startPage(pageNum, pageSize, "attr_id DESC");

3.9 注意事项:
  • 在使用排序时,我们发现pagehelper采用的是字符串拼接的形式,这样会有潜在的sql注入问题,这就要求我们在排序时必须严格校验排序的参数。必须与表或者实体类字段做好对应。

前端传参
@GetMapping("/findByPage")public Result<PageData<SpAttribute>> findByPage(@RequestParam(defaultValue = "1") Integer pageNum,    @RequestParam(defaultValue = "10") Integer pageSize) {pageSize = pageSize >= 50 ? 50 : pageSize;return ...}
注意事项:
  • pageNum,pageSize指定默认值

  • pageNum 可以不做限制但是pageSize必做,防止前端恶意传参

pageParam

import lombok.Getter;import static com.codingfuture.ssm.constant.ErpConstant.*;/*** @PROJECT_NAME: ssm* @DATE: 2023/10/26* @AUTHOR: Petrel* @DESCRIPTION:*/
@Getter
public class PageParam {/*** pageNum pageSize做处理*/private int pageNum =   DEFAULT_PAGE_NUM;private int pageSize = DEFAULT_PAGE_SIZE;public void setPageNum(int pageNum) {if (pageNum < ZERO) {throw new RuntimeException();}this.pageNum = pageNum;}public void setPageSize(int pageSize) {if (pageSize % PAGE_SIZE_STEP != ZERO|| pageSize > MAX_PAGE_SIZE|| pageSize <= ZERO) {throw new RuntimeException();}this.pageSize = pageSize;}}

constant

public interface ErpConstant {int ZERO = 0;int DEFAULT_PAGE_NUM = 1;int PAGE_SIZE_STEP = 5;int DEFAULT_PAGE_SIZE = 10;int MAX_PAGE_SIZE = 50;
}
pageHelper注意事项
  • 分页插件是当调用startPage或者offsetPage之后开始拦截select语句,拦截之后,在select语句后拼接limit参数,拦截以后,分页功能关闭,再准备拦截下一次select语句。也就是说如果我们连续发了2个select语句请求只会拦截第一次操作。

  • 不要在拦截select语句与请求的select语句之间使用page的任意方法,只有select语句请求以后,page里面才有数据。

4.0 事务

事务:transaction

4.1 基本使用

在你认为可能出现问题的方法上加上注解@Transactional

4.2 rollbackFor
  • 程序报错!尽管我们添加了事务注解,但是我们发现数据还是可以在数据库中进行修改

  • 实际上spring框架在封装 @Transactional注解默认只会处理runtimeException,对于编译异常,默认交给用户处理。

  • 我们希望编译异常也交给spring框架来管理,具体配置如下

  • @Transactional(rollbackFor = RuntimeException.class)//默认
    @Transactional(rollbackFor = Exception.class) // 所有 遇见运行时异常 或者 非运行时异常。都会回滚,前提是该方法内的异常抛出而非捕获

4.3 事务的传播机制
  • REQUIRED (默认)

    • 支持当前事务,如果当前没有事务,则新建事务

    • 如果当前存在事务,则加入当前事务,合并成一个事务

  • REQUIRES_NEW

    • 新建事务,如果当前存在事务,则把当前事务挂起(无论当前环境是否有事物)

    • 这个方法会独立提交事务,不受调用者的事务影响,父级异常,它也是正常提交

  • NESTED

    • 如果当前存在事务,它将会成为父级事务的一个子事务,方法结束后并没有提交,只有等父事务结束才提交

    • 如果当前没有事务,则新建事务

    • 如果它异常,父级可以捕获它的异常而不进行回滚,正常提交

    • 但如果父级异常,它必然回滚,这就是和 REQUIRES_NEW 的区别

  • SUPPORTS

    • 如果当前存在事务,则加入事务

    • 如果当前不存在事务,则以非事务方式运行,这个和不写没区别

  • NOT_SUPPORTED

    • 以非事务方式运行

    • 如果当前存在事务,则把当前事务挂起

  • MANDATORY

    • 如果当前存在事务,则运行在当前事务中

    • 如果当前无事务,则抛出异常,也即父级方法必须有事务

  • NEVER

    • 以非事务方式运行,如果当前存在事务,则抛出异常,即父级方法必须无事务

    • 一般用得比较多的是 REQUIREDREQUIRES_NEW

      REQUIRES_NEW 一般用在子方法需要单独事务。

  @Transactional(propagation = Propagation.REQUIRED)

4.4 事务的失效场景

5.0 Lombok

5.1 常用注解
@Getter
@Setter
@ToString
@EqualsAndHashCode
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
//    @Getterprivate Integer id;
//    @Setterprivate String name;private Integer age;
}
5.2 @Slf4j (日志框架)
编译前
@Slf4j
class Demo {public static void main(String[] args) {}
}
编译后
class Demo {private static final Logger log = LoggerFactory.getLogger(Demo.class);Demo() {}public static void main(String[] args) {// 日志输出级别:debug、info、warn、errorlog.debug();}
}
5.3 级别演示
@Slf4j
@Service
public class PersonServiceImpl implements PersonService {@Autowiredprivate PersonMapper personMapper;@Overridepublic List<Person> findList() {log.debug("开始打印数据");return personMapper.findList();}
}

注意:我们项目配置文件中配置日志的打印级别是debug,故会将所有的日志全部打印

#开发环境日志级别
logging.level.com.codingfuture.ssm_test=debug
#生产环境日志级别
#logging.level.com.codingfuture.ssm_test=info
#再次精简打印信息
logging.level.root=warn

5.4 调试打印
@Slf4j
@Service
public class PersonServiceImpl implements PersonService {@Autowiredprivate PersonMapper personMapper;@Overridepublic List<Person> findList() {List<Person> list = personMapper.findList();log.debug("开始打印{}集合数据",list);return  list;}
}
5.5 写入日志

#生产环境,将打印信息写到文件中
logging.file.name = logger.log

6.0 md5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/763115.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“低代码+平台”:驱动企业数字化转型与创新的新引擎

“低代码平台”作为一种新兴的软件开发范式&#xff0c;正逐渐成为企业快速响应市场变化、优化业务流程、提升数字化水平的重要手段。它的价值在于&#xff0c;将传统软件开发的复杂性大大降低&#xff0c;赋予了非技术人员或轻量级开发者快速构建应用的能力&#xff0c;并能灵…

【vue-小知识】var、let 和 const之间的区别

文章目录 结论1、重复定义变量名var&#xff1a;允许重复定义变量名let和const&#xff1a;不可以重复定义变量名 2、修改值var&#xff1a;允许修改值let&#xff1a;允许修改值const&#xff1a;不允许修改值&#xff0c;会报错 3、变量提升var : 支持变量提升let和const&…

吃瓜Grok大模型

段子区 今年当地时间2月29日晚&#xff0c;马斯克闹出来一件大事——正式起诉OpenAI和Sam Altman&#xff0c;并要求OpenAI 恢复开源GPT-4等模型。国际流量大师我只付服马斯克和川宝!&#xff01; 当大家觉得这扯皮的故事就此结束后&#xff0c;马斯克“不负众望”的整了一个大…

【网络取证箱】网络取证在线分析工具箱

【网络取证箱】网络取证在线分析工具箱 在线网站查询工具箱&#xff0c;没什么介绍的&#xff0c;所见即所得&#xff0c;在本文档里补充了其它一些网络安全资源&#xff0c;请忽用于非法活动&#xff0c;仅供学习研究—【蘇小沐】 &#xff08;一&#xff09;Whois查询 主要…

docker 进入容器内部命令

docker容器运行了&#xff0c;怎么进入容器内部查看内部的文件情况呢&#xff1f; 答&#xff1a;可以通过docker exec 的命令查看。 docker exec --help 可以查看命令介绍 &#xff1a; docker exec -it XXX /bin/bash XX为容器ID 进入容器内部 /bin/bash是需要添加的 不…

Java NIO和IO之间的区别

前言 NIO&#xff08;New IO&#xff09;&#xff0c;这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的&#xff0c;但实现方式不同&#xff0c;NIO主要用到的是块&#xff0c;所以NIO的效率要比IO高很多。在Java API中提供了两套NIO&#xff0c;一套是针对标准输入输出…

Vue3中基本数据类型为什么需要.value,,,引用类型不需要.value

1、在v3中使用基本数据类型&#xff08;如数字、字符串、布尔值&#xff09;时&#xff0c;如果你希望响应式地更新数据并触发视图更新,需要使用ref包裹基本数据类型,然后将基本数据类型转化为响应式对象;- - - 因此当你使用ref包裹基本数据类型时,实际上得到的是一个包含.valu…

B002-springcloud alibaba 微服务环境搭建

目录 创建父工程创建基础模块创建用户微服务创建商品微服务创建订单微服务微服务调用 创建父工程 新建项目springcloud-alibaba&#xff0c;本工程不需要写代码&#xff0c;删除src 导包 <parent><groupId>org.springframework.boot</groupId><artifact…

Linux上Mysql安装和部署(图文结合超详细)

1、首先将虚拟机装成功&#xff08;这里不做演示&#xff09; 2、df-h 查看光盘是否挂载&#xff0c;已挂载进行下一步&#xff0c;未挂载手动挂载 2.1、手动挂载 mount -o ro /dev/sr0 /media3、进入etc/yum.repos.d目录查看仓是否配置&#xff0c;若配置进行下一一步&#…

360企业安全浏览器兼容模式显示异常某个内容不显示 偶发现象 本地无法复现情况js

360企业安全浏览器兼容模式显示异常 &#xff0c;现象测试环境频发 &#xff0c;本地连测试无法复现&#xff0c;线上反馈问题。 出现问题的电脑为windows且使用360企业安全浏览器打开兼容模式可复现 复现过程&#xff1a; 不直接点击超链接跳转页面 &#xff0c;登录后直接通…

C++ 侯捷 程序设计(Ⅱ)兼谈对象模型 笔记

Conversion function 转换函数 侯捷老师使用分数 Fraction举例&#xff0c;分数理应可以被看作是小数 提供了Fraction类对象一个转换为double的方法&#xff0c;当碰到需要转换为double的情况下&#xff0c;会调用该方法。 黄色的就是转换函数&#xff0c;没有return type&am…

Python+appium自动化测试之如何控制App的启动和退出

由于本人使用的是Android设备做自动化测试&#xff0c;所以以下内容均基于Android系统做出的整理 一、启动app 启动app需要设置Capability参数&#xff0c;而Capability参数放在Desired Capalibity中&#xff0c;Desired Capalibity告诉Appium想要的自动化平台和应用程序&…

Flutter与Xamarin跨平台APP开发框架的区别

嘿&#xff0c;各位亲爱的朋友们&#xff01;大家好&#xff0c;我是咕噜铁蛋&#xff01;今天我们要探讨的话题是&#xff1a;Flutter与Xamarin这两款热门的跨平台APP开发框架。我深知选择合适的开发工具对于开发者来说有多么重要。那么&#xff0c;当我们需要开发跨平台应用时…

【机器学习】基于正余弦搜索算法优化的BP神经网络分类预测(SCA-BP)

目录 1.原理与思路2.设计与实现3.结果预测4.代码获取 1.原理与思路 【智能算法应用】智能算法优化BP神经网络思路【智能算法】正余弦优化算法&#xff08;SCA&#xff09;原理及实现 2.设计与实现 数据集&#xff1a; 多输入多输出&#xff1a;样本特征24&#xff0c;标签类…

高德地图——轨迹回放和电子围栏

功能点 地图的初始化显示电子围栏&#xff08;先初始化在调接口显示电子围栏&#xff09;显示定位显示轨迹轨迹回放 &#xff08;回放速度无法控制是因为高德地图的版本问题&#xff0c;不要设置版本&#xff0c;使用默认的即可生效&#xff09;获取当前城市及天气情况设置地图…

【漏洞复现】金和OA IncentivePlanFulfill.aspx SQL注入漏洞

0x01 产品简介 金和OA协同办公管理系统C6软件&#xff08;简称金和OA&#xff09;&#xff0c;本着简单、适用、高效的原则&#xff0c;贴合企事业单位的实际需求&#xff0c;实行通用化、标准化、智能化、人性化的产品设计&#xff0c;充分体现企事业单位规范管理、提高办公效…

黑马现有java课程框架及其功能梳理

目录 高并发相关提高通信效率Netty作用&#xff1a;哪些框架使用它&#xff1a; ChannelChannelHandler 和 ChannelPipelineEventLoop 和 EventLoopGroup**涉及的名词解释&#xff1a;**NIOSocketNginx 高并发相关 主要用来解决IO密集型程序&#xff08;大量文件读写&#xff…

盲盒小程序有什么优势?如何运营获客?

盲盒作为当下的热门行业&#xff0c;已经在国内外成功站稳脚步&#xff0c;市场规模庞大。 线上盲盒小程序也是互联网电商下的新模式&#xff0c;将传统的盲盒模式与线上电商模式相结合&#xff0c;为消费者提供一种新颖额盲盒购买体验&#xff0c;玩家在手机上就可以体验到抽…

HTML5+CSS3小实例:具有悬停效果的3D闪耀动画

实例:具有悬停效果的3D闪耀动画 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, init…

2024年卫生巾行业市场分析报告(京东天猫淘宝线上卫生巾品类电商数据查询)

最近&#xff0c;相关部门辟谣了一则“十大致癌卫生巾黑名单”的消息。这个榜单是部分博主AI撰写&#xff0c;为博眼球、蹭热度的结果。此次事件势必会对卫生巾行业产生一定影响&#xff0c;加剧行业竞争。 根据鲸参谋电商数据平台显示&#xff0c;2024年1月至2月线上电商平台…