REST风格(Representational State Transfer),表现形式状态装换,是一种软甲架构风格
传统方式定义URL: 定义复杂,且将资源访问行为暴露
REST风格:定义URL更简洁、更加规范、更加优雅
传统方式 | Restful | |
---|---|---|
http://localhost:80/dept/selectById?id=1 | GET http://localhost:80/dept/1 | 获取部门 |
http://localhost:80/dept/deleteById?id=1 | DELETE http://localhost:80/dept/1 | 删除单个资源 |
http://localhost:80/dept/insert | POST http://localhost:80/dept | 创建单个部门 |
http://localhost:80/dept/update | PUT http://localhost:80/dept | 修改单个部门 |
http://localhost:80/dept/selectAll | GET http://localhost:80/dept | 获取所有部门 |
注意事项:
● 上述行为是风格,是约定方式,约定不是规范,可以打破,所以称为 REST风格,而不是REST规范。
●描述模块的功能通常使用复数,也就是加s的格式来描述,表示此类资源,而非单个资源。如:users、emps、books…
- 拥有http的优点:本身就是http,无状态,不用关心两次访问上下文,不像重定向和转发需要关注当前路径。
- 充分利用HTTP协议本身语义:原来只用get,post,现在还要用delete和put,patch。
前端传输数据 | 后端匹配请求 + 接收数据 |
---|---|
GET http://localhost/dept/1 | @GetMapping(“/dept/{id}”) + @PathVariable(“id”) Long id |
Post http://localhost/dept - 对象:{} | @PostMapping(“/dept”) + @RequestBody Dept dept |
复杂表单数据【文件上传】name=“file” | @PostMapping(“/dept”) +@RequestPart(“file”) MultipartFile file |
@GetMapping | 等价于:@RequestMapping( method = {RequestMethod.GET} ) |
---|---|
@PostMapping | 等价于:@RequestMapping( method = {RequestMethod.POST} ) |
@PathVariable | 从路径中获取变量 |
@RequestBody | 从请求体【请求数据包中】中获取数据 |
@RequestPart | 获取复杂表单数据或获取二进制文件数据 |
前端发送请求,后端Controller层进行接收,Controller层调用Service层进行业务逻辑处理,Service调用Mapper层进行数据处理,然后先将数据持久化存储(数据库中),然后返回给Service层->返回给Controller层,最后返回给前端。
在前端开发中,分页功能通常需要传递以下参数到后台:
- 当前页码(Page):表示当前所请求的页数。
- 每页数量(PageSize):表示每页要显示的数据条数。
后台简化分页开发的插件 :PageHelper
PageHelper 是一个非常受欢迎的 Java 分页插件,它可以简化后台的分页逻辑。下面是使用 PageHelper 插件的示例:
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.4.2version>
dependency>
yaml
# MySQL 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/example
spring.datasource.username=root
spring.datasource.password=password
# MyBatis 配置
mybatis.configuration.map-underscore-to-camel-case=true
# PageHelper 配置
pagehelper.helper-dialect=mysql
pagehelper.params=count=countSql
import com.github.pagehelper.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface UserDao {
Page<User> getUsersByPage(@Param("page") int page, @Param("pageSize") int pageSize);
}
<select id="getUsersByPage" resultType="com.example.User">
SELECT * FROM users
</select>
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public List<User> getUsersByPage(int page, int pageSize) {
PageHelper.startPage(page, pageSize);
Page<User> userPage = userDao.getUsersByPage(page, pageSize);
return userPage.getResult();
}
}
创建部门表(Department):在数据库中创建一个用于存储部门信息的表。
前端页面设计:创建一个前端页面,用于输入新增部门所需的信息,例如部门名称、描述等。可以使用 HTML、CSS 和 JavaScript来设计和验证输入表单。
后端接口设计:设计一个后端接口,用于处理前端传递过来的新增部门请求。可以使用 HTTP 协议,并按照 RESTful 风格进行接口设计。
后端业务逻辑实现:在后端编程语言中,实现新增部门的业务逻辑。具体实现过程可能包括以下步骤:
- 验证输入数据:对前端传递过来的数据进行验证,确保数据的合法性和完整性,例如必填字段的校验。
- 创建部门对象:使用输入数据创建部门对象,将数据存储在对象的属性中。
- 调用数据访问层:调用数据访问层(DAO)的方法,将部门对象保存到数据库中。
数据访问层实现:在数据访问层中,执行与数据库交互的操作,例如将部门对象保存到数据库中。
异常处理:考虑并处理可能发生的异常情况,例如数据库连接异常、数据重复异常等。可以使用 try-catch或全局异常处理器来捕获和处理异常。
返回结果:根据新增部门的结果,将相应的响应信息返回给前端,例如成功提示或错误提示等。
前端展示结果:根据后端返回的结果,在前端页面上展示相应的提示信息,例如成功提示、错误提示或重新加载等。
前端页面设计:创建一个前端页面或界面元素,用于触发删除操作。可以使用按钮、链接或其他交互元素来表示删除操作。
后端接口设计:设计一个后端接口,用于处理前端传递过来的删除部门请求。可以使用 HTTP 协议,并按照 RESTful 风格进行接口设计。
后端业务逻辑实现:在后端编程语言中,实现删除部门的业务逻辑。具体实现过程可能包括以下步骤:
- 根据前端传递过来的部门唯一标识(例如部门ID),查询数据库获取对应的部门信息。
- 判断部门是否存在,如果不存在则返回错误信息;如果存在,则执行删除操作。
- 调用数据访问层(DAO)的方法,从数据库中删除指定的部门记录。
数据访问层实现:在数据访问层中,执行与数据库交互的操作,例如从数据库中删除指定的部门记录。
异常处理:考虑并处理可能发生的异常情况,例如数据库连接异常、权限验证等。可以使用 try-catch 块或全局异常处理器来捕获和处理异常。
返回结果:根据删除操作的结果,将相应的响应信息返回给前端,例如成功提示或错误提示等。
前端展示结果:根据后端返回的结果,在前端页面上展示相应的提示信息,例如成功提示、错误提示或重新加载等。
注意:
删除部门操作涉及到数据库中的数据删除,因此在实现时需要谨慎操作,确保只删除指定的部门记录。同时,要考虑到与其他表之间的关联关系,例如是否需要级联删除相关的员工信息等。
前端页面设计:创建一个前端页面或界面元素,用于输入查询条件或触发查询操作。可以使用输入框、下拉列表、按钮等来实现查询条件的输入。
后端接口设计:设计一个后端接口,用于处理前端传递过来的查询部门请求。可以使用 HTTP 协议,并按照 RESTful 风格进行接口设计。
后端业务逻辑实现:在后端编程语言中,实现查询部门的业务逻辑。具体实现过程可能包括以下步骤:
- 解析前端传递过来的查询条件,例如部门名称、部门ID等。
- 调用数据访问层(DAO)的方法,根据查询条件从数据库中获取符合条件的部门信息。
数据访问层实现:在数据访问层中,执行与数据库交互的操作,例如根据查询条件从数据库中获取部门信息。
异常处理:考虑并处理可能发生的异常情况,例如数据库连接异常、数据查询异常等。可以使用 try-catch或全局异常处理器来捕获和处理异常。
返回结果:将从数据库中查询到的部门信息返回给前端,可以使用 JSON 格式进行数据的序列化和传输。
前端展示结果:根据后端返回的结果,在前端页面上展示查询到的部门信息,例如表格、列表或其他形式的展示。
注意:
查询部门操作需要根据具体的查询条件进行筛选和过滤,以获取符合条件的部门信息。可以根据需要实现不同的查询方式,例如根据部门名称进行模糊查询、根据部门ID进行精确查询等。
同部门查询
员工查询逻辑:
前端页面设计:创建一个前端页面或界面元素,用于输入查询条件或触发查询操作。可以使用输入框、下拉列表、按钮等来实现查询条件的输入。
后端接口设计:设计一个后端接口,用于处理前端传递过来的查询员工请求。可以使用 HTTP 协议,并按照 RESTful 风格进行接口设计。
后端业务逻辑实现:在后端编程语言中,实现查询员工的业务逻辑。具体实现过程可能包括以下步骤:
- 解析前端传递过来的查询条件,例如员工姓名、部门ID等。
- 调用数据访问层(DAO)的方法,根据查询条件从数据库中获取符合条件的员工信息。
数据访问层实现:在数据访问层中,执行与数据库交互的操作,例如根据查询条件从数据库中获取员工信息。
异常处理:考虑并处理可能发生的异常情况,例如数据库连接异常、数据查询异常等。可以使用 try-catch或全局异常处理器来捕获和处理异常。
返回结果:将从数据库中查询到的员工信息返回给前端,可以使用 JSON 格式进行数据的序列化和传输。
前端展示结果:根据后端返回的结果,在前端页面上展示查询到的员工信息,例如表格、列表或其他形式的展示。
分页查询:
前端页面设计:在前端页面中,添加分页控件,例如分页导航栏、页码输入框等。
后端接口设计:在后端接口中,增加分页查询相关的参数,例如页码和每页记录数。
后端业务逻辑实现:在后端业务逻辑中,根据传入的页码和每页记录数,计算出需要查询的起始位置和截止位置。然后,在查询数据库时使用这个范围进行查询,以获取特定页的员工信息。
数据访问层实现:在数据访问层中,根据查询条件和分页参数,构造 SQL 查询语句,使用 LIMIT 和 OFFSET 子句来限制查询的结果集。
返回结果:将查询到的员工信息及分页相关的信息返回给前端,例如总记录数、当前页码、总页数等。
前端展示结果:根据后端返回的结果,在前端页面上展示查询到的员工信息,并更新分页导航栏等。
注意:
在分页查询时,应当考虑性能和用户体验方面的因素。可以结合数据库的索引、缓存等技术手段来优化查询效率,并允许用户指定每页记录数、跳转至指定页等操作,以提供更好的用户体验。
同部门删除:
前端页面设计:创建一个前端页面或界面元素,用于选择要删除的员工并触发删除操作。可以使用复选框、表格等来展示员工列表和选择要删除的员工。
后端接口设计:设计一个后端接口,用于处理前端传递过来的删除员工请求。可以使用 HTTP 协议,并按照 RESTful 风格进行接口设计。
后端业务逻辑实现:在后端编程语言中,实现删除员工的业务逻辑。具体实现过程可能包括以下步骤:
- 解析前端传递过来的要删除的员工ID或其他标识。
- 调用数据访问层(DAO)的方法,根据员工ID或标识,从数据库中删除相应的员工记录。
数据访问层实现:在数据访问层中,执行与数据库交互的操作,例如执行 SQL 删除语句,从数据库中删除员工记录。
异常处理:考虑并处理可能发生的异常情况,例如数据库连接异常、数据删除异常等。可以使用 try-catch
块或全局异常处理器来捕获和处理异常。返回结果:根据删除操作的结果,返回相应的成功或失败消息给前端,可以使用 JSON 格式进行数据的序列化和传输。
前端展示结果:根据后端返回的结果,在前端页面上展示删除操作的结果消息,例如弹出提示框或刷新员工列表等。
注意:
删除操作涉及到对数据的永久性删除,因此在执行删除操作之前应当进行必要的权限验证和确认操作,以确保只有具备相应权限的用户才能执行删除操作,并避免误操作导致数据丢失
@sfl4j
- 表单必须有 file 域,用于选择要上传的文件。
- 表单提交方式必须为 POST。
- 表单的编码类型enctype必须要设置为 multipart/form-data。
MultipartFile类型
- 本地存储:
缺点:
● 不安全:磁盘如果损坏,所有的文件就会丢失。
● 容量有限:如果存储大量的图片,磁盘空间有限(磁盘不可能无限制扩容)。
● 无法直接访问
解决方案:
● 自己搭建文件存储系统,如:fastDFS
● 自己搭建对象存储服务,如:MinIO
●使用现成的云服务,如:阿里云,腾讯云,华为云
- 阿里云oss集成存储
先根据ID查询员工信息,进行数据查询回显,然后修改数据.
当修改完数据之后,点击保存按钮,就需要将数据提交到服务端,然后服务端需要将数据保存到数据库中
@Value 注解通常用于外部配置的属性注入,具体用法为: @Value(“${配置文件中的key}”)
@ConfigurationProperties
1). 定义实体类,用于封装需要注入的属性。
2). 在工具类中,注解注入上述的bean对象,然后调用get方法就可以获取到各个属性
- properties
- yml(推荐)
- yaml
- xml
由于浏览器与web服务器中的数据交互是通过HTTP协议的,而HTTP协议是无状态的–即每个页面中的请求和响应都是独立的,没有状态存在。
所以我们需要进行登录校验
思路:
- 在员工登录成功后,需要将用户登录成功的信息存起来,记录用户已经登录成功的标记。
- 在浏览器发起请求时,需要在服务端进行统一拦截,拦截后进行登录校验。
- 会话技术
- 统一拦截技术
统一拦截技术实现方案也有两种:
- Servlet规范中的Filter过滤器
- Spring提供的interception拦截器
用户在前端页面输入用户名和密码,并点击登录按钮。
前端使用 JavaScript 验证用户输入的数据是否符合规则,例如检查用户名和密码是否为空,长度是否符合要求等。
前端将验证通过的用户名和密码通过 HTTP 请求发送给后端。
后端接收到登录请求后,从数据库或其他存储系统中查询与用户名匹配的用户信息。
后端对比查询到的用户信息中的密码与用户输入的密码是否一致。
如果密码一致,表示登录成功,后端生成一个认证凭证(例如 JSON Web Token)作为登录状态标识,并将其返回给前端。
前端接收到登录成功的响应后,可以将认证凭证保存在客户端(如 Cookie 或 LocalStorage)中,用于后续的身份验证和授权操作。
如果密码不一致或未查询到对应的用户信息,表示登录失败,后端返回相应的错误信息给前端。
前端根据后端返回的结果进行相应的处理,例如显示错误提示信息、清空输入框等。
具体实现时,可以使用以下技术和步骤:
前端:使用 HTML、CSS 和 JavaScript 实现登录页面,使用 AJAX 或 Fetch API发送登录请求,接收后端返回的结果并进行处理。
后端:使用后端编程语言(如 Python、Java、Node.js 等)实现登录校验的接口。在接口中,使用数据库查询语句(如 SQL 语句)查询用户信息,并进行密码比对,最后返回相应的结果。
数据库:存储用户信息,包括用户名和密码等字段。可以使用关系型数据库(如 MySQL、PostgreSQL)或非关系型数据库(如MongoDB)。
注意:
登录校验过程中需要注意数据安全性和用户隐私保护。应对密码进行加密存储,并使用安全的传输协议(如 HTTPS)保护登录请求和响应的安全性。同时,在实现过程中也需要考虑异常处理、防止暴力破解、验证码等安全措施。
会话技术是指在客户端和服务器之间保持状态的一系列技术,用于实现用户登录状态的跟踪和信息共享。以下是几种常见的会话技术:
Cookie: Cookie 是最常见的会话技术之一。服务器可以通过在响应中设置 Set-Cookie 头来将一个小的数据片段发送到客户端,并在后续的请求中由客户端自动发送回服务器。这个数据片段可以包含用户登录状态信息或其他需要保持的会话数据。
Session: Session 是服务器端的一种会话技术。当用户访问服务器时,服务器会为每个用户创建一个唯一的会话标识符(Session ID),并将该标识符发送给客户端(通常通过 Cookie)。服务器会在后续的请求中使用该会话标识符来查找关联的会话数据。会话数据通常存储在服务器的内存或持久化存储中(例如数据库)。
JSON Web Token (JWT): JWT 是一种开放标准 (RFC 7519),用于在客户端和服务器之间传输声明式的、经过加密签名的令牌。JWT 可以包含用户的身份认证信息和其他额外的声明数据,并且由服务器生成和签名。令牌可以在客户端保存,然后在后续的请求中作为授权凭证发送给服务器进行验证。
==URL ==参数: 可以将会话信息作为 URL 的查询参数传递给服务器。例如,在链接中包含用户的身份标识或令牌。服务器在每个请求中从 URL 参数中提取会话信息,并进行相应的处理。
Web Storage: Web Storage 是在客户端浏览器上存储数据的一种机制,包括 localStorage 和 sessionStorage。这些机制允许开发者将键值对形式的数据存储在客户端中,并且在后续的会话中可以读取和修改。
Cookie 和 Session 是最常见的会话技术,适用于大多数 Web 应用程序。JWT 对于分布式系统和 API 授权较为常见。URL 参数通常用于简单的身份验证场景。Web Storage 适用于需要在客户端保存状态的场景。
JWT令牌由Header、Payload、Signature三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz
{
"alg":"HS256",
"type":"JWT"
}
将上边的内容使用Base64编码,得到一个字符串就是JWT令牌的第一部分。
{
"id":"1",
"username":"Tom"
}
将第二部分负载使用Base64编码,得到一个字符串就是JWT令牌的第二部分。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
base64UrlEncode(header):jwt令牌的第一部分。
base64UrlEncode(payload):jwt令牌的第二部分。
secret:签名所使用的密钥
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.1version>
dependency>
public class JwtDemo {
@Test
public void genJwt(){
Map<String,Object> claims = new HashMap<>();
claims.put("id",1);
claims.put("username","Tom");
String jwt = Jwts.builder()
.setClaims(claims) //执行第二部分负载, 存储的数据
.signWith(SignatureAlgorithm.HS256, "itheima") //签名算法及秘钥
.setExpiration(new Date(System.currentTimeMillis() + 12*3600*1000)) //设置令牌的有效期
.compact();
System.out.println(jwt);
}
}
@Test
public void parseJwt(){
Claims claims = Jwts.parser()
.setSigningKey("itheima")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjU5OTk1NTE3LCJ1c2VybmFtZSI6IlRvbSJ9.EUTfeqPkGslekdKBezcWCe7a7xbcIIwB1MXlIccTMwo")
.getBody();
System.out.println(claims);
}
注意事项:
● JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
● 如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。
在登录成功之后,生成JWT令牌并返回给浏览器。
- 步骤:
- 引入JWT工具类
- 登录完成后,调用工具类生成JWT令牌并返回
public class JwtUtils {
private static String signKey = "itheima";
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
Emp e = empService.login(emp);
if(e != null){ //用户名密码正确
Map<String,Object> claims = new HashMap<>();
claims.put("id",e.getId());
claims.put("username",e.getUsername());
claims.put("name",e.getName());
//生成JWT令牌
String jwt = JwtUtils.generateJwt(claims);
return Result.success(jwt);
}
return Result.error("用户名或密码错误");
}
}
在服务端统一拦截校验JWT令牌,两种手段实现:过滤器Filter、拦截器Interceptor
● 概念:Filter 过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。
● 过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
● 过滤器一般完成一些通用的操作,比如:登陆鉴权、统一编码处理、敏感字符处理等等…
使用步骤:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.39</version>
</dependency>
public class DemoFilter implements Filter {
/**
*
* @param servletRequest 负责处理客户端发送过来的请求(获取参数)
* @param servletResponse 负责服务端响应数据给客户端
* @param filterChain 过滤链,实现是否进行拦截(截停,放行)
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
}
}
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
}
}
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("拦截方法执行, 拦截到了请求 ...");
System.out.println("执行放行前逻辑 ...");
chain.doFilter(request, response);
System.out.println("执行放行后逻辑 ...");
}
}
@ServletComponentScan
@SpringBootApplication
public class TliasWebManagementApplication {
public static void main(String[] args) {
SpringApplication.run(TliasWebManagementApplication.class, args);
}
}
● 放行后访问对应资源,资源访问完成后,会回到Filter中
● 如果回到Filter中,执行的是放行后的逻辑
Filter 拦截路径:
@WebFilter(urlPatterns = "/*")
拦截路径 | urlPattern值 | 含义 |
---|---|---|
拦截具体路径 | /login | 只有访问 /login 路径时,才会被拦截 |
目录拦截 | /emps/* | 访问/emps下的所有资源,都会被拦截 |
拦截所有 | /* | 访问所有资源,都会被拦截 |
● 拦截器:(Interceptor)是一种动态拦截方法调用的机制,类似于过滤器。在SpringMVC中动态拦截控制器方法的执行
● 作用:在指定的方法调用前后执行预先设定的代码,完成功能增强
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行 , true : 放行 ; false : 不放行,拦截 ;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle ....");
//如果校验通过放行
return false;
}
//目标资源方法执行后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle ....");
}
//请求处理完成后调用
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion ....");
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
拦截路径 | urlPattern值 | 含义 |
---|---|---|
拦截具体路径 | /login | 只有访问 /login 路径时,才会被拦截 |
目录拦截 | /emps/* | 访问/emps下的下一级资源,如: /emps/1 ,但是 不会拦截 /emps/list/1,/emps/list/1/2 |
目录拦截 | /emps/** | 访问/emps下的所有资源,都会被拦截 |
拦截所有 | /** | 访问所有资源,都会被拦截 |
● 方案一:在Controller的方法中进行try…catch处理 (代码过于臃肿)
● 方案二:全局异常处理器
SpringMVC中提供了全局异常处理器接收所有Controller中产生的异常。一般定义在exception包下:
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* Exception异常分类
* - 运行时异常 : RuntimeException , 编译时无需处理 .
* - 编译时异常 : 非 RuntimeException , 编译时处理 .
*/
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("系统繁忙, 请稍后重试 ... ");
}
}
事务是什么?在MySQL中是怎么去开启,提交,回滚事务的。
在Spring中怎么管理事务,用什么注解,在那个层次进行使用可以有效管理事务
事务管理时规则:如果方法能够正常执行完自动提交事务,如果出现异常自动回滚事物。事务默认识别的异常是运行时异常,如果想要识别到编译时异常从而实现回滚,该怎么操作?
事务的传播方式有哪些,含义是怎样?
事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
属性值 含义 说明
REQUIRE 【默认值】需要事务,有则加入,无则创建新事务 -
REQUIRES_NEW 需要新事务,无论有无,总是创建新事务 -
SUPPORTS 支持事务,有则加入,无则在独立的连接中运行 SQL 结合 Hibernate、JPA 时有用,配在查询方法上
NOT_SUPPORTED 不支持事务,不加入,在独立的连接中运行 SQL -
MANDATORY 必须有事务,否则抛异常 -
NEVER 必须没事务,否则抛异常 -
NESTED 嵌套事务 仅对 DataSourceTransactionManager 有效
AOP叫做什么,有什么作用?举一个5岁孩子就能理解的例子?
AOP(Aspect-Oriented Programming)是一种面向切面编程的编程范式。它的作用是通过将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,实现对系统中不同模块之间的共享功能和行为的集中管理。
让我们用一个简单的例子来解释 AOP,并让一个5岁的孩子理解:
假设你有一个画画的小朋友,他正在画一幅漂亮的风景画。他要使用不同的颜色绘制天空、山、树和花等元素。现在,他想要在每个元素上都添加相同的效果-闪光。为了实现这个功能,可以使用 AOP。
在传统的编程方法中,小朋友需要为每个元素手动添加闪光效果。但是,如果使用 AOP,小朋友只需定义一个闪光的切面(Aspect),然后将这个切面应用到每个元素上。这样,当小朋友绘制每个元素时,闪光效果会自动地被添加上去,无需手动重复代码。
换句话说,小朋友只需专注于绘制每个元素的细节,而不需要担心添加闪光效果这个横切关注点。这样,他可以更加专注于画画的创造性过程,而不用分心去管理共享的闪光效果。
这个例子中,小朋友就是核心业务逻辑(绘制各个元素),而闪光效果就是一个横切关注点。AOP 的作用就是将这个横切关注点从核心业务逻辑中分离出来,使得核心业务逻辑更加清晰、简洁,并提供了可重用和集中管理的机制。
如果要完成一个AOP的入门案例,需要有哪些步骤?
pom.xml 引入依赖
定义类抽取公共代码(执行耗时统计操作)
标识当前类是一个AOP类,并被Spring容器管理
配置公共代码作用于哪些目标方法
执行目标方法
AOP的概念理解:连接点,通知,切入点,切面 ?
通知有哪些类型?
如果有不同切面的通知,增强相同的方法,执行顺序是怎样的?
切点表达式有几种,具体怎么定义?
如果有多个通知的切点表达式一样,怎么抽取?
连接点是什么可以获取哪些信息?