目录
创建springboot项目
目录结构:
启动类
测试类
idea建表
pom文件
编写yml文件
qq邮箱设置
登陆注册代码
编写持久层(Dao)
注册代码
业务层
业务实现类
mapper
控制层
前端代码
注册页面
邮件正文:
登录代码
控制层
业务层:
业务实现类:
前端代码
自动登录
创建springboot项目
Maven类型+
Lombok依赖+spring web依赖+MySQL driver依赖+mybatis framework依赖+java Mail Sender依赖
目录结构:
有些类是自己写的不用看,看一下结构就可以
启动类
@SpringBootApplication @MapperScan("com.example.mapper")//将mapper路径下自动注册映射器接口为spring Bean public class SpringBootDemo1Application {public static void main(String[] args) {SpringApplication.run(SpringBootDemo1Application.class,args);} }
测试类
@SpringBootTest @RunWith(SpringRunner.class) class SpringBootTestApplicationTests {}
idea建表
use `数据库名`;
create table `user`(`id` int primary key auto_increment comment '主键id',`email` varchar(255) comment '用户邮箱',`password` varchar(255) comment '用户密码',`salt` varchar(255) comment '盐',`confirm_code` varchar(255) comment '确认码',`activation_time` datetime comment '激活时间',`is_valid` tinyint comment '账号状态'
)default charset=utf8 comment '用户表';
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>springBoot-Test</artifactId><version>0.0.1-SNAPSHOT</version><name>springBoot-Test</name><description>springBoot-Test</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.6.13</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.2.0</version><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><!--导入Mybatis坐标--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.2</version></dependency><!--导入mybatis-plus坐标--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><!--导入数据库druid坐标--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.22</version></dependency><!--简略get,set方法--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency><!--模版引擎--><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!--添加事务管理--><!-- 支持使用 Spring AOP 和 AspectJ 进行切面编程。 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- SpringBoot集成FreeMarker的依赖 :模版引擎,生成输出文本--><!--<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency>--><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!--邮箱发送--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><!--工具包:雪花算法:生成确认码--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.25</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.springboottest.SpringBootTestApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>
编写yml文件
server:port: 8088 spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driver # 配置数据库驱动程序,用于数据库通信和执行sql语句url: jdbc:mysql://localhost:3306/表名?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 # 加数据库名username: rootpassword: mvc: # 处理springboot与swagger2冲突pathmatch:matching-strategy: ant_path_matcherfreemarker:expose-session-attributes: true # 暴露session对象的属性settings:classic_compatible: true # 配置为传统模式,控制自动处理suffix: .ftl # 指定模版文件后缀mail:protocol: smtp # 邮箱协议host: smtp.qq.com # qq邮箱,如果用网易将qq改成163port: 25username: # 发送人邮件名(这个地方可能出错,可能是由于名字问题)password: # 授权码default-encoding: utf-8properties:mail:debug: true # 开启debug模式会打印邮件发送过程的日志mybatis-plus:# mybatis映射器XML文件位置 作用:定义sql语句和结果映射mapper-location: classpath:mapper/*.xml# 开启mybatis-plus的运行日志(建议)configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
qq邮箱设置
点击第二列的账号:开启服务,发送邮件,记下授权码 ok !
登陆注册代码
编写持久层(Dao)
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "user")
public class User {@TableId(value = "id",type = IdType.AUTO)private Integer id;@TableField(value = "email")private String email;@TableField(value = "password") // 密码,使用md5+盐加密private String password;@TableField(value = "salt")private String salt; // 盐@TableField(value = "confirm_code") // 确认码private String confirmCode;@TableField(value = "activation_time") // 激活失效时间private LocalDateTime activationTime;@TableField(value = "is_valid") // 账号状态private Byte isValid;}
注册代码
业务层
public interface UserService extends IService<User> {// 创建账号Map<String,Object> createAccount(User user);// 创建账号过程中,用于激活账号的确认码,没有激活不可以登录账号Map<String, Object> activation(String confirmCode);// 将用户信息录入数据库int insertUser(User user);// 通过确认码查找用户,不用担心确认码重复User selectUserByConfirmCode(String confirmCode);// 通过邮箱激活账号int updateUserByConfirmCode(String confirmCode);// 通过邮箱名查找用户(如果没有进行注册查重,那么将这个修改成List<User>有多个用户报异常)User selectUserByEmail(String email);
}
业务实现类
@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper um;@Value("${spring.mail.username}")private String mailUsername; @Resource //发送邮件,实现邮箱验证private JavaMailSender javaMailSender; @Resource // 模版引擎private TemplateEngine templateEngine;@Override@Transactional // 事务管理/** 创建账号:接收发送过来的邮件账号和密码,利用雪花算法生成确认码用于激活账号,使用MD5将密码进行加密* 设置激活时间和激活状态为未激活后添加到数据库,发送邮件领取激活码,激活账号*/public Map<String, Object> createAccount(User user) {// 检验账号是否重复// 雪花算法生成确认码String confirmCode = IdUtil.getSnowflake(1,1).nextIdStr();// 生成盐 随机数String salt = RandomUtil.randomString(6);// 加密密码:原始密码+盐String md5Pwd = SecureUtil.md5(user.getPassword()+salt);// 激活时间 有效时间LocalDateTime ldt = LocalDateTime.now().plusDays(1);user.setConfirmCode(confirmCode);user.setSalt(salt);user.setPassword(md5Pwd);user.setActivationTime(ldt);user.setIsValid((byte)0);// 新增账号int result = um.insert(user);HashMap<String, Object> hm = new HashMap<>();if(result > 0){// 发送邮件:前端会调用该路径下的方法并传递确认码参数String activationUrl = "http://localhost:8088/user/activation?confirmCode=" + confirmCode;sendMailForActivationAccount(activationUrl,user.getEmail());hm.put("code",200);hm.put("message","注册成功。请前往邮件进行账号激活");}else {hm.put("code",400);hm.put("message","注册失败");}return hm;}@Override@Transactional/*发送邮件申请激活账号:创建邮件,设置主题、发送者、接受者、发送日期、创建上下文环境(编写在 html)*/public void sendMailForActivationAccount(String activationUrl, String email) {// 创建邮件对象MimeMessage mimeMessage = javaMailSender.createMimeMessage();try {MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);// 设置邮箱主题message.setSubject("抖音账号激活");// 设置邮件发送者message.setFrom(mailUsername);// 设置邮件接受者(可以设置多个)message.setTo(email);// 设置邮件发送日期message.setSentDate(new Date());// 创建上下文环境(正文) 用thymeleafContext context = new Context();// 将url注入html中,在html中直接用// 当在页面点击链接时,会直接执行路径中方法context.setVariable("activationUrl",activationUrl);String text = templateEngine.process("activation-account.html",context);message.setText(text,true);} catch (MessagingException e) {throw new RuntimeException(e);}// 发送邮件javaMailSender.send(mimeMessage);}@Override/*在注册阶段会调用该方法实现账号激活:根据注册阶段传递过来的确认码查询用户,调取用户信息判断是否是有效激活时间,返回结果*/public Map<String, Object> activation(String confirmCode) {Map<String, Object> hm = new HashMap<>();// 根据确认码查询用户User user = um.selectUserByConfirmCode(confirmCode);// 判断激活时间是否失效:现在时间是在激活时间之后吗boolean after = LocalDateTime.now().isAfter(user.getActivationTime());if(after){hm.put("code",400);hm.put("message","激活失效,请重启注册");return hm;}// 修改状态值int result = um.updateUserByConfirmCode(confirmCode);if(result > 0){hm.put("code",200);hm.put("message","激活成功");return hm;}else {hm.put("code",400);hm.put("message","激活失效,请联系管理员");return hm;}}@Overridepublic int insertUser(User user) {return um.insert(user);}@Overridepublic User selectUserByConfirmCode(String confirmCode) {return um.selectUserByConfirmCode(confirmCode);}@Overridepublic int updateUserByConfirmCode(String confirmCode) {return um.updateUserByConfirmCode(confirmCode);}@Overridepublic User selectUserByEmail(String email) {return um.selectUserByEmail(email);}}
mapper
public interface UserMapper extends BaseMapper<User> {/** 根据确认码查询用户*/@Select("SELECT email,activation_time FROM user WHERE confirm_code = #{confirmCode} AND is_valid = 0")User selectUserByConfirmCode(@Param("confirmCode") String confirmCode);/** 根据确认码查询用户并修改状态码为1*/@Update("UPDATE user SET is_valid = 1 WHERE confirm_code = #{confirmCode}")int updateUserByConfirmCode(@Param("confirmCode") String confirmCode);/** 根据邮箱查询用户*/@Select("SELECT * FROM user WHERE email = #{email} AND is_valid = 1")User selectUserByEmail(@Param("email") String email);}
控制层
@Api("用户界面")
@RestController
@RequestMapping("user")
public class UserController {@Resourceprivate UserService us;@ApiOperation(value = "注册账号")@PostMapping("create")public Map<String,Object> createAccount(@RequestBody User user){return us.createAccount(user);}@ApiOperation(value = "激活账号")@GetMapping("activation")/*通过邮件激活相当于网页传递数据。因为路径中追加了confirmCode所以会自动传参*/public Map<String,Object> activation(String confirmCode){return us.activation(confirmCode);}}
前端代码
因为用的是thymeleaf写的所以目录结构如下(记得写在templates中)
注册页面
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><!-- 引入 jQuery --><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script><style>body {background: url('https://cdn.pixabay.com/photo/2018/08/14/13/23/ocean-3605547_1280.jpg') no-repeat;background-size: 100% 130%;}#login_box {width: 20%;height: 400px;background-color: #00000060;margin: auto;margin-top: 10%;text-align: center;border-radius: 10px;padding: 50px 50px;}h2 {color: #ffffff90;margin-top: 5%;}#input-box {margin-top: 5%;}span {color: #fff;}input {border: 0;width: 60%;font-size: 15px;color: #fff;background: transparent;border-bottom: 2px solid #fff;padding: 5px 10px;outline: none;margin-top: 10px;}button {margin-top: 50px;width: 60%;height: 30px;border-radius: 10px;border: 0;color: #fff;text-align: center;line-height: 30px;font-size: 15px;background-image: linear-gradient(to right, #30cfd0, #330867);}#sign_up {margin-top: 45%;margin-left: 60%;}a {color: #b94648;}</style>
</head><body>
<div id="login_box"><h2>REGISTRY</h2><div id="input_box"><input type="text" id = "email" name="email" placeholder="请输入用户名"></div><div class="input_box"><input type="password" id = "password" name="password" placeholder="请输入密码"></div><button id = "registry">注册</button><br><br><p>Come to us ? <a href="login">Login</a></p></div>
/*当id:registry发生点击行为thymeleaf会接受相应过来的数据并转换成json格式,然后调用url路径下的方法创建账号* result接收控制层返回的数据(Map)在网页提示创建成功或创建失败*/
<script type="text/javascript" charset="UTF-8">$("#registry").on("click",function (){$.ajax({url:"/user/create",type: "POST",contentType: "application/json",data: JSON.stringify({ email: $("#email").val(),password: $("#password").val()}),dataType: "json",success: function(result){alert(result.message);},error: function(result){alert("发生错误");}});});
</script>
</body>
</html>
邮件正文:
<html>
<body>
<!--根据自己需要编写,-->
<div><p>Email 地址验证</p> <!--target:新的窗口打开超链接--><p>这封信是由<a href="https://www.douyin.com" target = "_blank">抖音</a>发送的</p><p>由于你在抖音进行了新用户注册或用户修改,如果你没有进行过此操作,请忽略这封邮件。如果你是新用户或者修改你的账号请点击下方链接:</p><p><a th:href="@{${activationUrl}}"><span th:text="${activationUrl}"></span></a>感谢你的访问,祝你生活愉快。</p></div>
</body>
</html>
登录代码
控制层
登录界面:http://localhost:8088/gameLogin/login
@Api(value = "登录页面")
@Controller
@RequestMapping("gameLogin")
public class LoginController {@Resourceprivate UserService us;@GetMapping("login") public String login(){return "login";}@GetMapping("registry")public String registry(){return "registry";}@PostMapping("loginAccount")@ResponseBodypublic Map<String,Object> loginAccount(@RequestBody User user){return us.loginAccount(user);}
}
业务层:
public interface UserService extends IService<User> {Map<String,Object> loginAccount(User user);
}
业务实现类:
@Override/** 登录账号*/public Map<String, Object> loginAccount(User user) {Map<String, Object> hm = new HashMap<>();User user1 = um.selectUserByEmail(user.getEmail());// 如果账号不存在或未激活if(user1 == null || user1.getIsValid() == (byte)0){hm.put("code",400);hm.put("message","该账户不存在或未激活");return hm;}// 进行密码比对String md5Pwd = SecureUtil.md5(user.getPassword()+user1.getSalt());if(!md5Pwd.equals(user1.getPassword())){hm.put("code",400);hm.put("message","用户名或密码错误");return hm;}hm.put("code",200);hm.put("message","登陆成功");return hm;}
前端代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><!-- 引入 jQuery --><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script><style>body {background: url('https://cdn.pixabay.com/photo/2018/08/14/13/23/ocean-3605547_1280.jpg') no-repeat;background-size: 100% 130%;}#login_box {width: 20%;height: 400px;background-color: #00000060;margin: auto;margin-top: 10%;text-align: center;border-radius: 10px;padding: 50px 50px;}h2 {color: #ffffff90;margin-top: 5%;}#input-box {margin-top: 5%;}span {color: #fff;}input {border: 0;width: 60%;font-size: 15px;color: #fff;background: transparent;border-bottom: 2px solid #fff;padding: 5px 10px;outline: none;margin-top: 10px;}button {margin-top: 50px;width: 60%;height: 30px;border-radius: 10px;border: 0;color: #fff;text-align: center;line-height: 30px;font-size: 15px;background-image: linear-gradient(to right, #30cfd0, #330867);}#sign_up {margin-top: 45%;margin-left: 60%;}a {color: #b94648;}</style>
</head><body>
<div id="login_box"><h2>LOGIN</h2><div id="input_box"><input type="text" id="email" name="email" placeholder="请输入用户名"></div><div class="input_box"><input type="password" id="password" name="password" placeholder="请输入密码"></div><button id = "login">登录</button><br><br><p>New to us ? <a href="registry">Registry</a></p>
</div>
<script type="text/javascript" charset="UTF-8">$("#login").on("click",function (){$.ajax({url:"/gameLogin/loginAccount",type: "POST",contentType: "application/json",data: JSON.stringify({ // 将对象转化为json格式email: $("#email").val(),password: $("#password").val()}),dataType: "json",success: function(result){alert(result.message);if(200 == result.code) {window.location.href = "https://www.douyin.com"}},error: function(result){alert("发生错误");}});});
</script>
</body>
</html>
自动登录
package com.example.utils;import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringBootConfiguration;@SpringBootConfiguration
public class AutoStartLogin implements CommandLineRunner {@Overridepublic void run(String ... args) {try {Runtime.getRuntime().exec("cmd /c start http://localhost:8088/gameLogin/login");} catch (Exception ex) {ex.printStackTrace();}}
}