周末帮一个朋友写了一个SpringBoot+Vue的项目,抽时间整理一下里面的常用的技术点。
前端使用的 Element UI 模板。
代码地址:https://github.com/saysky/petition-system-server
一、效果图和项目结构
1.先看下效果图
2、然后贴一下前端项目结构
Login.vue 是登录页面的 vue 文件,Identify.vue 是验证码的
二、vue 前端代码
Login.vue
{{errInfo}}
@keyup.enter.native="submitForm('ruleForm')">
登录
注册
export default {
name: 'login',
data() {
return {
identifyCodes: "1234567890",
identifyCode: "",
errorInfo: false,
ruleForm: {
name: '',
password: '',
validate: ''
},
rules: {
name: [
{required: true, message: '请输入登录名', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'}
],
validate: [
{required: true, message: '请输入验证码', trigger: 'blur'}
]
}
}
},
mounted() {
this.identifyCode = "";
this.makeCode(this.identifyCodes, 4);
},
methods: {
submitForm(formName) {
const self = this;
self.$refs[formName].validate((valid) => {
if (valid) {
if (self.ruleForm.validate != this.identifyCode) {
self.errorInfo = true;
self.errInfo = '验证码错误';
self.$message.error('验证码错误');
this.refreshCode();
} else {
self.$http.post('/api/user/login', self.ruleForm)
.then((response) => {
console.log(response);
if (response.data.code == -1) {
self.errorInfo = true;
self.errInfo = response.data.msg;
self.$message.error(response.data.msg);
// 重新生成验证码
this.refreshCode()
} else if (response.data.code == 0) {
self.$message.success(response.data.msg);
self.$router.push('/home');
sessionStorage.setItem('session_username', self.ruleForm.name);
sessionStorage.setItem('session_user', JSON.stringify(self.ruleForm));
console.log(JSON.stringify(self.ruleForm));
}
}).then((error) => {
console.log(error);
})
}
} else {
console.log('error submit!!');
return false;
}
});
},
gotoRegister() {
this.$router.push('/register');
},
randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min);
},
refreshCode() {
this.identifyCode = "";
this.makeCode(this.identifyCodes, 4);
},
makeCode(o, l) {
for (let i = 0; i < l; i++) {
this.identifyCode += this.identifyCodes[
this.randomNum(0, this.identifyCodes.length)
];
}
console.log(this.identifyCode);
},
}
}
.login-wrap {
position: relative;
width: 100%;
height: 100%;
}
.ms-title {
position: absolute;
top: 50%;
width: 100%;
margin-top: -230px;
text-align: center;
font-size: 30px;
color: #fff;
}
.ms-login {
position: absolute;
left: 50%;
top: 50%;
width: 300px;
height: 240px;
margin: -150px 0 0 -190px;
padding: 40px;
border-radius: 5px;
background: #fff;
}
.ms-login span {
color: red;
}
.login-btn {
text-align: center;
}
.login-btn button {
width: 100%;
height: 36px;
}
.code {
width: 112px;
height: 35px;
border: 1px solid #ccc;
float: right;
border-radius: 2px;
}
.validate-code {
width: 136px;
float: left;
}
.register {
font-size: 14px;
line-height: 30px;
color: #999;
cursor: pointer;
float: right;
}
Identify.vue
export default{
name: 'SIdentify',
props: {
identifyCode: {
type: String,
default: '1234'
},
fontSizeMin: {
type: Number,
default: 16
},
fontSizeMax: {
type: Number,
default: 40
},
backgroundColorMin: {
type: Number,
default: 180
},
backgroundColorMax: {
type: Number,
default: 240
},
colorMin: {
type: Number,
default: 50
},
colorMax: {
type: Number,
default: 160
},
lineColorMin: {
type: Number,
default: 40
},
lineColorMax: {
type: Number,
default: 180
},
dotColorMin: {
type: Number,
default: 0
},
dotColorMax: {
type: Number,
default: 255
},
contentWidth: {
type: Number,
default: 112
},
contentHeight: {
type: Number,
default: 38
}
},
methods: {
// 生成一个随机数
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
// 生成一个随机的颜色
randomColor (min, max) {
let r = this.randomNum(min, max)
let g = this.randomNum(min, max)
let b = this.randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
},
drawPic () {
let canvas = document.getElementById('s-canvas')
let ctx = canvas.getContext('2d')
ctx.textBaseline = 'bottom'
// 绘制背景
ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax)
ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
// 绘制文字
for (let i = 0; i < this.identifyCode.length; i++) {
this.drawText(ctx, this.identifyCode[i], i)
}
this.drawLine(ctx)
this.drawDot(ctx)
},
drawText (ctx, txt, i) {
ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei'
let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))
let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
var deg = this.randomNum(-45, 45)
// 修改坐标原点和旋转角度
ctx.translate(x, y)
ctx.rotate(deg * Math.PI / 180)
ctx.fillText(txt, 0, 0)
// 恢复坐标原点和旋转角度
ctx.rotate(-deg * Math.PI / 180)
ctx.translate(-x, -y)
},
drawLine (ctx) {
// 绘制干扰线
for (let i = 0; i < 8; i++) {
ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
ctx.beginPath()
ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
ctx.stroke()
}
},
drawDot (ctx) {
// 绘制干扰点
for (let i = 0; i < 100; i++) {
ctx.fillStyle = this.randomColor(0, 255)
ctx.beginPath()
ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
ctx.fill()
}
}
},
watch: {
identifyCode () {
this.drawPic()
}
},
mounted () {
this.drawPic()
}
}
三、后端代码
后端采用 SpringBoot
登录接口代码如下
@PostMapping(value = "/api/user/login", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Response login(@RequestBody User user,
HttpSession session) {
User u = userService.findByUserName(user.getName());
if (u == null) {
return Response.no("用户名不存在!");
}
if (!Objects.equals(u.getPassword(), user.getPassword())) {
return Response.no("密码不正确!");
}
session.setAttribute("session_user", u);
return Response.yes("登录成功", u);
}
User.java
package com.example.sens.entity;
import java.io.Serializable;
import java.util.Date;
/**
*
* 用户信息
*
*/
@Data
public class User implements Serializable {
private static final long serialVersionUID = -5144055068797033748L;
/**
* 用户ID
*/
private Long id;
/**
* 用户名
*/
private String name;
/**
* 密码
*/
private String password;
/**
* 姓名
*/
private String realName;
}
注意:@Data 是使用 lombok 的注解,如果您那边没有安装或引入lombok依赖,可以生成 getter/setter 来替代
Response.java
package com.example.sens.util;
import lombok.Data;
@Data
public class Response {
private Integer code;
private String msg;
private T data;
public Response() {
}
public Response(Integer code) {
this.code = code;
}
public Response(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Response(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static Response yes() {
return new Response(0, "操作成功");
}
public static Response yes(String msg,T data) {
return new Response(0, msg, data);
}
public static Response yes(T data) {
return new Response(0, "操作成功", data);
}
public static Response no() {
return new Response(-1, "操作失败");
}
public static Response no(String msg) {
return new Response(-1, msg);
}
}
需要完整代码,可以联系博主