Day 7
距离 Day 6 已经过去了一个多月啊!额…课设已经验收了,不过验收时我课设其实还没做完,不过验收就那几分钟老师也不可能能验出来我课设没做完的地方。验收的老师可以说比较”严谨“了,注重的是数据库有没有联表查询、有没有视图,用没用索引啥的…我就只有联表,如果 Mysql 默认的主键索引算的话索引页可以加上qwq。其他有的老师重视的就是整体的工程,比如:
看我acm退役后,学期结束前有没有时间搞鼓吧…大概率是懒得管这个的。
今天晚上状态不好于是想着整理下课设,理应是要刷题准备周末这赛季我的第一场 XCPC 的,不过也算是换个心情好了。
验收前加急添加的两个稍微还算是有点实际作用的功能:
1、Mybatis 动态 SQL 实现主页面的多条件搜索;
2、邮件发送验证码修改密码。
当时网上搜了半天,全都是使用 xml 映射文件里的标签实现的,而我课设里面的 mapper 都是注解实现的,于是为了这个搜索 sql 专门开了个 xml 版本的 mapper。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace用于绑定mapper接口-->
<mapper namespace="com.campusrecruit.mapper.PositionMapper2">
<!-- 通过 xml 中的 if 标签实现动态 sql -->
<select id="getPositionList" resultType="com.campusrecruit.bean.Position">
select * from `position` where 1 = 1
<if test="keyword != null"> AND `name` like '%${keyword}%'</if>
<if test="type != null"> AND `type` like '%${type}%'</if>
<if test="sort != null"> AND `sort` like '%${sort}%'</if>
</select>
</mapper>
其实还是挺简单的,<if>
标签里 test
的语句为真的话就把标签里面的语句拼接上去。由于是在由引号 ‘ ’ 包裹的字符串里面所以用 ${}
来引入变量而非 #{}
,前者是把数据原封不懂的传到 sql 语句里,后者会以引号 ‘ ‘或“ ” 包裹的形式作为字符串出入 sql 语句里(我很好奇传数字时它在数字两端添引号 sql 怎么识别,以前都是这么用还不知道这点)。后者(#{}
)可以有效防止 sql 注入。开头的那个 where 1 = 1
是方便后面拼接 sql 语句方便,不然还要判是不是第一个条件要额外添加 where
, 1 = 1
这个条件在较高版本的 mysql 里会被优化掉。
效果(搜索框里的“软件”是我打上去的,我还没做搜索条件回显到页面的功能,点搜索后表单会被“初始化”)
邮件发送验证码找回密码:
直接 copy JavaEE作业里的邮件服务,开一个 Service 层:
哦这个 Service 层后面应该要复盘,我课设写到后面也是深深意识到 Service 层的重要性。
@Service
public class MailService {
@Autowired
private JavaMailSender mailSender;
private String from = "QQ Number@qq.com";
public void sendCheckCode(String to, String code) {
try {
SimpleMailMessage message = new SimpleMailMessage(); //简单邮件消息对象
message.setFrom(from); //发送方
message.setTo(to); //接收方
message.setSubject("修改密码"); //邮件主题
String content = "您正在通过邮箱验证的方式修改您在本校园招聘平台的密码, 如果这不是您的操作, 请忽略.\n";
content += "您的验证码: ";
content += code;
content += "\n";
content += "该验证码 30 分钟内有效。请勿将您的验证码告与他人.";
System.out.println("to = " + to + ", content = " + content);
message.setText(content); //邮件内容
mailSender.send(message); //发送邮件
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后前端用 .ajax 调用中间 Controller 层封装的发送邮件的方法,不过当时没时间,验证码直接在前台用 js 生成,这应该是不安全的…吧?
// 发送验证码
var code = "";
$('#sendCheckCode').click(function () {
let to = $('#formContent3 input[name=Rmail]').val();
let all = "a1b2c3d4e5f6g7h8y9z1x23456789";
code = "";
for(let i=0; i<6; i++) {
code += all[ Math.floor( Math.random() * 1000 ) % all.length ];
}
$.ajax({
url: "/sendCheckCode",
data: {"to":to, "code":code},
type: 'post',
success: function () {
alert("验证码已发送");
},
error:function () {
alert("error");
}
})
})
效果:
还有一些是当初验收当天演完了后,晚上即兴做的一些修改:
一个涉及到事务:添加了 Service 层用于添加新的账户
因为我的数据库里的有关用户的表,分为了三个部分,账户(account)存储账号信息,人员(People) 存基本信息,学生/职员(student/employee) 存身份信息,添加一个新用户就要向三个表插入数据。我在验收前插入测试数据时(包括更久之前我写课设添加新公司添加新的职员管理账号时),经常出现有的表的数据插入失败的情况(大多是由于之前删除账户没删干净,id 重了),但又有的表的数据插入进去了,其实这要么都插入失败,要么就都成功。这就要用到事务。Springboot + Mybatis 实现事务很简单,就加个注解:@Transactional
(另外启动类还要添加一个 @EnableTransactionManagement
注解)
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// Service 层通过事务实现添加人员时相关表中数据一致性
@Transactional
public void addNewStudent(String username, String password,
String name, Integer sex, Integer age, String mail, String tele, String ino,
String school, String sno, String major, Integer graduate) {
userMapper.addAccount(username, password, 1);
Long id = userMapper.getLastID();
userMapper.addPeople(id,name,sex,age,mail,tele,ino);
userMapper.addStudent(id,school,sno,major,graduate);
// System.out.println("Add new student finished...");
}
}
附带温习一下事务 ASID:
- 原子性
- 一致性
- 隔离性
- 持久性