本节代码开源地址
用户注册前端
1.在src/api下创建/auth/auth.js
import request from '@/utils/request' export function userRegister(UserDTO) { return request({ url: '/auth/user/register', method: 'post', data: UserDTO }) }
2.在src/views创建/auth/register.vue
<template> <div class="columns py-6"> <div class="column is-half is-offset-one-quarter"> <el-card shadow="never"> <div slot="header" class="has-text-centered has-text-weight-bold">新用户入驻</div> <div> <el-form ref="ruleForm" v-loading="loading" :model="ruleForm" status-icon :rules="rules" label-width="100px" class="demo-ruleForm" > <el-form-item label="账号" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="密码" prop="pass"> <el-input v-model="ruleForm.pass" type="password" autocomplete="off" /> </el-form-item> <el-form-item label="确认密码" prop="checkPass"> <el-input v-model="ruleForm.checkPass" type="password" autocomplete="off" /> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="ruleForm.email" autocomplete="off" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm('ruleForm')">立即注册</el-button> <el-button @click="resetForm('ruleForm')">重置</el-button> </el-form-item> </el-form> </div> </el-card> </div> </div> </template> <script> import { userRegister } from "@/api/auth/auth"; export default { name: "Register", data() { const validatePass = (rule, value, callback) => { if (value === "") { callback(new Error("请再次输入密码")); } else if (value !== this.ruleForm.pass) { callback(new Error("两次输入密码不一致!")); } else { callback(); } }; return { loading: false, ruleForm: { name: "", pass: "", checkPass: "", email: "" }, rules: { name: [ { required: true, message: "请输入账号", trigger: "blur" }, { min: 2, max: 10, message: "长度在 2 到 10 个字符", trigger: "blur" } ], pass: [ { required: true, message: "请输入密码", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" } ], checkPass: [ { required: true, message: "请再次输入密码", trigger: "blur" }, { validator: validatePass, trigger: "blur" } ], email: [ { required: true, message: "请输入邮箱地址", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] } ] } }; }, methods: { submitForm(formName) { this.$refs[formName].validate(valid => { if (valid) { this.loading = true; userRegister(this.ruleForm) .then(value => { const { code, message } = value; if (code === 200) { this.$message({ message: "账号注册成功", type: "success" }); setTimeout(() => { this.loading = false; this.$router.push({ path: this.redirect || "/login" }); }, 0.1 * 1000); } else { this.$message.error("注册失败," + message); } }) .catch(() => { this.loading = false; }); } else { return false; } }); }, resetForm(formName) { this.$refs[formName].resetFields(); } } }; </script> <style scoped> </style>
3.测试页面
image-20210211232353719
用户注册后端
1.实体类
import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder;ums_user import lombok.experimental.Accessors; import java.io.Serializable; import java.util.Date; @Data @Builder @TableName("ums_user") @NoArgsConstructor @AllArgsConstructor @Accessors(chain = true) public class UmsUser implements Serializable { private static final long serialVersionUID = -5051120337175047163L; @TableId(value = "id", type = IdType.ASSIGN_ID) private String id; @TableField("username") private String username; @TableField("alias") private String alias; @JsonIgnore() @TableField("password") private String password; @Builder.Default @TableField("avatar") private String avatar = "https://s3.ax1x.com/2020/12/01/DfHNo4.jpg"; @TableField("email") private String email; @TableField("mobile") private String mobile; @Builder.Default @TableField("bio") private String bio = "自由职业者"; @Builder.Default @TableField("score") private Integer score = 0; @JsonIgnore @TableField("token") private String token; @Builder.Default @TableField("active") private Boolean active = true; /** * 状态。1:使用,0:已停用 */ @Builder.Default @TableField("`status`") private Boolean status = true; /** * 用户角色 */ @TableField("role_id") private Integer roleId; @TableField(value = "create_time", fill = FieldFill.INSERT) private Date createTime; @TableField(value = "modify_time", fill = FieldFill.INSERT_UPDATE) private Date modifyTime; }
2.mapper接口
public interface UmsUserMapper extends BaseMapper<UmsUser> { }
3.DTO
import lombok.AllArgsConstructor; import lombok.Data; import org.hibernate.validator.constraints.Length; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; @Data @AllArgsConstructor public class RegisterDTO { @NotEmpty(message = "请输入账号") @Length(min = 2, max = 15, message = "长度在2-15") private String name; @NotEmpty(message = "请输入密码") @Length(min = 6, max = 20, message = "长度在6-20") private String pass; @NotEmpty(message = "请再次输入密码") @Length(min = 6, max = 20, message = "长度在6-20") private String checkPass; @NotEmpty(message = "请输入电子邮箱") @Email(message = "邮箱格式不正确") private String email; }
4.controller
@RestController @RequestMapping("/auth/user") public class UmsUserController { @Autowired private UmsUserService umsUserService; /** * 注册 * * @param registerDTO 接收参数 * @return */ @PostMapping("/register") private ApiResult register(@RequestBody RegisterDTO registerDTO) { Boolean register = umsUserService.register(registerDTO); return ApiResult.success(register); } }
5.service
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.notepad.blog.common.api.ApiResult; import com.notepad.blog.common.exception.ApiAsserts; import com.notepad.blog.domain.UmsUser; import com.notepad.blog.domain.dto.RegisterDTO; import com.notepad.blog.mapper.UmsUserMapper; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import java.util.Date; @Service public class UmsUserService extends ServiceImpl<UmsUserMapper, UmsUser> { public UmsUser register(RegisterDTO registerDTO) { // 查询是否有相同的用户名 String userName = registerDTO.getName(); String email = registerDTO.getEmail(); LambdaQueryWrapper<UmsUser> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UmsUser::getUsername, userName) .or() .eq(UmsUser::getEmail, userName); UmsUser umuser = this.getOne(queryWrapper); if (!ObjectUtils.isEmpty(umuser)) { ApiAsserts.fail("账号或邮箱已存在"); } // 否则注册 UmsUser umsUser = UmsUser.builder() .username(userName) .alias(userName) .password(registerDTO.getPass()) .email(email) .createTime(new Date()) .status(true) .build(); this.save(umsUser); return umsUser; } }
密码加密
package com.notepad.blog.common.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Utils { public static String getPwd(String pwd) { try { // 创建加密对象 MessageDigest digest = MessageDigest.getInstance("md5"); // 调用加密对象的方法,加密的动作已经完成 byte[] bs = digest.digest(pwd.getBytes()); // 接下来,我们要对加密后的结果,进行优化,按照mysql的优化思路走 // mysql的优化思路: // 第一步,将数据全部转换成正数: String hexString = ""; for (byte b : bs) { // 第一步,将数据全部转换成正数: // 解释:为什么采用b&255 /* * b:它本来是一个byte类型的数据(1个字节) 255:是一个int类型的数据(4个字节) * byte类型的数据与int类型的数据进行运算,会自动类型提升为int类型 eg: b: 1001 1100(原始数据) * 运算时: b: 0000 0000 0000 0000 0000 0000 1001 1100 255: 0000 * 0000 0000 0000 0000 0000 1111 1111 结果:0000 0000 0000 0000 * 0000 0000 1001 1100 此时的temp是一个int类型的整数 */ int temp = b & 255; // 第二步,将所有的数据转换成16进制的形式 // 注意:转换的时候注意if正数>=0&&<16,那么如果使用Integer.toHexString(),可能会造成缺少位数 // 因此,需要对temp进行判断 if (temp < 16 && temp >= 0) { // 手动补上一个“0” hexString = hexString + "0" + Integer.toHexString(temp); } else { hexString = hexString + Integer.toHexString(temp); } } return hexString; } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; } public static void main(String[] args) { String pwd = MD5Utils.getPwd("234"); System.out.println(pwd); } }
404页面
1.在src/views创建/error/404.vue
<template> <div class="columns mt-6"> <div class="column mt-6"> <div class="mt-6"> <p class="content">UH OH! 页面丢失</p> <p class="content subtitle mt-6"> 您所寻找的页面不存在, {{ times }} 秒后,将返回首页! </p> </div> </div> </div> </template> <script> export default { name: "404", data() { return { times: 10 } }, created() { this.goHome(); }, methods: { goHome: function () { this.timer = setInterval(() => { this.times-- if (this.times === 0) { clearInterval(this.timer) this.$router.push({path: '/'}); } }, 1000) } } } </script> <style scoped> </style>
2.配置路由
,{ path: '/404', name: '404', component: () => import('@/views/error/404'), meta: {title: '404-Notfound'} },{ path: '*', redirect: '404', hidden: true }