- @ControllerAdvice
- 用于修饰类,表示该类是Controller的全局配置类
- 在此类中,可以对Controller进行如下三种全局配置:
- 异常处理方案
- 绑定数据方案
- 绑定参数方案
- @ExceptionHandler
- 用于修饰方法,该方法会在Controller出现异常后被调用,用于处理捕获到的异常
- @ModelAttribute
- 用于修饰方法,该方法会在Controller方法执行前被调用,用于为Model对象绑定参数
- @DataBinder
- 用于修饰方法,该方法会在Controller方法执行前被调用,用于绑定参数的转换器
私信列表相关
发表于
分类于
牛客讨论区项目
- 私信列表
- 查询当前用户会话列表,每个会话只显示最新私信
- 支持分页
- 私信详情
- 查询某个会话所包含的私信
- 支持分页
评论相关模块
显示评论
- 数据层
- 根据实体查询一页评论数据
- 根据实体查询评论的数量
- 业务层
- 处理查询评论的业务
- 处理查询评论数量的业务
- 表现层
- 显示帖子详情数据时,同时显示该帖子所有评论数据
注意点
- 由于评论也有回复,所以Controller层返回的List是两层嵌套的
- 注意判断回复的性质,是给帖子的还是给评论的
- 前端渲染方面:
- rvo,cvo遍历链表
- cvoStat.count,获取当前遍历的下表
- 分页可以复用主页的
增加评论
- 数据层
- 增加评论数据
- 修改帖子评论数量
- 业务层
- 处理添加评论业务
- 增加评论
- 更新评论数量
- 处理添加评论业务
- 表现层
- 处理添加评论数据的请求
- 设置添加评论的表单
业务层需要事务管理
- 因为增加评论和更新评论数量这两步是原子的
- 隔离级别与传播机制分别为READ_COMMITTED与REQUIRED
Spring事务管理
- 声明式事务
- 通过XML配置,声明某方法的事务特征
- 通过注解,声明某方法的事务特征
- 编程式事务
- 通过TransactionTemplate管理事务,并通过它执行数据库操作
@Transactional注解
- isolation:事务隔离级别
- propagation:事务传播机制
- REQUIRED:支持当前事务(外部事务),如果不存在则创建新事物
- REQUIRES_NEW:创建一个新事务,并且暂停当前事务
- NESTED:如果当前存在事务,则嵌套在该事务中执行,否则同REQUIRED
TransactionTemplate类
- .setIsolationLevel(TransactionDefinition.):设置隔离级别
- .setPropagationBehavior(TransactionDefinition.):设置传播机制
- .execute(new TransactionCallback
敏感词过滤
简单的敏感词过滤器
- 定义字典树
- 根据敏感词文件初始化字典树
- 编写敏感词过滤的方法
一些技巧
- 判断特殊符号
1 | private boolean isSymbol(Character c) { |
- 获取文件缓冲流
1 | InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt"); |
Interceptor拦截器
如何创建拦截器?
- 在Controller层实现HandlerInterceptor接口
- 有三个可实现的方法
- preHandle方法,在Controller之前执行
- postHandle方法,在调用Controller之后执行
- afterCompletion方法,在模板引擎TemplateEngine之后执行
如何使用拦截器?
- 继承WebMvcConfigurer类,实现addInterceptors方法
1 | @Configuration |
登录模块开发
基本功能
- 访问登陆界面
- 登录
- 验证账号,密码,验证码
- 成功时,生成登陆凭证,返回给客户端
- 失败时,跳转回登录页
- 退出
- 将登陆凭证改为失效状态
- 跳转回首页
登录
- Service层
- 接收账号密码,在数据库中查找,返回错误信息
- 若信息无误,生成登陆凭证,传给Controller层
- Controller层
- 接收post请求,验证验证码是否正确
- 若验证码正确,将账号密码发送给Service层进行验证
- 接受错误信息,传给model
- 若无误,跳转回主页(重定向,return “redirect:/index”;)
退出登录
- Service层
- 接收Controller层传来的登陆凭证,修改状态
- Controller层
- 接收get请求,退出登录,将登陆凭证传给Controller层
- 重定向到登陆界面
拦截器应用
- 在请求开始时查询登录用户
- 在本次请求中持有用户数据
- 在模板视图上显示用户数据
- 在请求结束时清理用户数据
权限控制
- 登陆检查
- 之前采用拦截器实现登陆检查,更换为更安全的权限管理方案
- 授权配置
- 对当前系统内包含的所有的请求,分配访问权限
- 认证方案
- 绕过Security认证流程,采用系统原来的认证方案
- CSRF配置
- 防止CSRF攻击的基本原理,以及表单、AJAX相关的配置
21级第二场排位赛题解
发表于
分类于
题解
A. IP Checking(LightOJ - 1354)
送分题?
- 不会有人连二进制转换都不会吧
参考代码:
1 | #include<bits/stdc++.h> |
B. Alexey and Train(Codeforces - 1501A)
阅读理解签到题
- 每次都是 $2$ 选 $1$,要不等到 $b_i$ ,要不就等待 $ \lceil \dfrac{b_i-a_i}{2} \rceil$ 的时间
参考代码:
1 | #include<bits/stdc++.h> |
C. C+=(Codeforces - 1368A)
签到题
每次将小的加上大的,易证这样操作一定是最优的
每次一个数一定至少会翻倍,所以暴力模拟的复杂度为 $\log n$,直接模拟即可
参考代码:
1 | #include<bits/stdc++.h> |
D. Max and Mex(Codeforces - 1496B)
分类讨论
- 如果 $mex(a)>max(a)$,那么每一次都会添加一个 $mex(a)$,之后 $mex(a)$ 和 $max(a)$ 都会加1,所以答案是 $ n+k$ 。
- 否则$mex(a)$ 和 $max(a)$ 永远不变,答案最多只会加$1$。
参考代码:
1 | #include<bits/stdc++.h> |
E. AND 0, Sum Big(Codeforces - 1514B)
考察对位运算的理解,沾点高中数学
- 由于 $and$ 运算对于每一个二进制位都是独立的,所以我们每一位都分开考虑。注意这是大部分位运算题目的解题思想
- $and$ 为 $0$,说明这 $n$ 个数对于单独的一个二进制位来说,至少有一个是 $0$
- 要求和最大,说明对于一个二进制位,只有一个数是$0$
- 利用乘法原理,容易得出答案
参考代码:
1 | #include<bits/stdc++.h> |
F. Constanze’s Machine(Codeforces - 1195C)
听说有同学不喜欢读题也不喜欢DP?
- 考虑动态规划:$f[i][0/1/2]$ 表示选取了编号在 $i$ 及以前的球员,所能得到的身高总和最大值
- 其中,第二维的 $0$ 表示编号为 $i$ 的球员一个都不选;$1$ 表示只选上面一个;$2$ 表示只选下面一个。(显然没有上下都选的情况)
- 状态转移方程:
- $f[i][0]=max(f[i−1][0],f[i−1][1],f[i−1][2])$
- $f[i][1]=max(f[i−1][0],f[i−1][2])+h[i][1]$
- $f[i][2]=max(f[i−1][0],f[i−1][1])+h[i][2]$
参考代码:
1 | #include <bits/stdc++.h> |
G. Pair of Topics(Codeforces - 1324D)
解法不唯一,给出二分解法
- 设 $c[i]=a[i]-b[i]$,并将其按照从小到大排序
- 对于每个 $i$,二分寻找满足条件最小的 $j$,统计答案
- 答案要开 $long long$
参考代码:
1 | #include<bits/stdc++.h> |
H. Fox And Two Dots(Codeforces - 510B)
题目中的手机游戏链接:https://www.taptap.com/app/2221?hreflang=zh_CN
- 题意很简单,连通块找环,注意细节即可
- $DFS$ 或 $BFS$ 均可,这里给出 $DFS$ 写法
参考代码:
1 | #include<bits/stdc++.h> |
Kaptcha生成验证码
基本步骤
导入jar包
编写Kaptcha配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@Configuration
public class KaptchaConfig {
@Bean
public Producer kaptchaProducer() {
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width", "100");
properties.setProperty("kaptcha.image.height", "40");
properties.setProperty("kaptcha.textproducer.font.size", "32");
properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
properties.setProperty("kaptcha.textproducer.char.length", "4");
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
DefaultKaptcha kaptcha = new DefaultKaptcha();
Config config = new Config(properties);
kaptcha.setConfig(config);
return kaptcha;
}
}
引入bean,生成随机字符,生成图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@RequestMapping(path="/kaptcha", method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response, HttpSession session) {
//生成验证码
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
//存入session
session.setAttribute("kaptcha", image);
//将图片输出给浏览器
response.setContentType("image/png");
try {
OutputStream os = response.getOutputStream();
ImageIO.write(image, "png", os);
} catch (IOException e) {
logger.error("响应验证码失败" + e.getMessage());
}
}