- 通过这个demo,会有以下几点收获
- 对前端模块有一个比较清晰的认识,比如这个demo实现的自定义密码校验、向后台发送请求、前端回显操作数据等
1.登录
1.1.前端
先来瞄一眼<template>中的html程序,其中有几个点可以学习
- 这个是表单头,其中ref是这个表单的名字,这里的ref在点击登录之后的点击函数login之后的校验会有用,如下:
- 这里有个样式,this.$message可以用来输出信息,留一下即可
- 同样是这个表单头,第二个属性rules是官方提供的进行数据校验的,通过v-model和vue对象中的rules进行双向数据绑定,如下:
- 这是一个典型的数据校验,required:true表示该字段是必填的,如果不填,则校验不通过,message表示当校验不通过时,用来返回给用户的信息,trigger:blur表示当该字段失去焦点时,就会触发校验,但是要注意,在表单项中还要添加prop属性,来指定rules校验中的username、password、code三个字段该和哪个<input>中的数据进行相关联,如下:
- 上面的rules中的code字段是自定义的校验规则,如下:
- 这里的validataCode和上面的rules中的validator后面的validataCode相对应,rule表示当前校验的对象,value表示当前字段的值,callback是一个回调函数,用来返回校验的结果
- 这里还有一个细节,value.toLowerCase()表示将输入的验证码转换为小写,在后面的获取验证码的函数中也有一个将获取的验证码转化为小写的过程,这里就在下面一个模块里讲
- 前端页面的验证码模块是怎么获取的?这里是直接找的网上的资源,代码放在下边了
- 下面的代码,如何生成验证码的,这里就不做解释了,主要关注下它是怎么把验证码传出来的,这里使用了
this.$emit
来触发一个名为update:value
的自定义事件,并将处理后的codeList
数组作为参数传递给该事件,我们在将这个组件引入之后,就需要从这个事件中来获取验证码,引入组件和获取验证码的程序如下:引入组件:
获取验证码:
- 自此,从验证码组件中生成的验证码,我们已经成功的封装到我们自己vue对象中的code里了,之后就是拿这个code和用户输入的code进行验证,这里上面已经讲了
还有最后一个功能,如何转到注册页面?
<template>
<div class="ValidCode disabled-select"
:style="`width:${width}; height:${height}`"
@click="refreshCode">
<span v-for="(item, index) in codeList"
:key="index"
:style="getStyle(item)">
{{item.code}}
</span>
</div>
</template>
<script>
export default {
name: "ValidCode",
model: {
prop: 'value',
event: 'input'
},
props: {
width: {
type: String,
default: '100px'
},
height: {
type: String,
default: '34px'
},
length: {
type: Number,
default: 4
}
},
data () {
return {
codeList: []
}
},
mounted () {
this.createdCode()
},
methods: {
refreshCode () {
this.createdCode()
},
createdCode () {
const len = this.length
const codeList = []
const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789'
const charsLen = chars.length
// 生成
for (let i = 0; i < len; i++) {
const rgb = [Math.round(Math.random() * 220), Math.round(Math.random() * 240), Math.round(Math.random() * 200)]
codeList.push({
code: chars.charAt(Math.floor(Math.random() * charsLen)),
color: `rgb(${rgb})`,
fontSize: `1${[Math.floor(Math.random() * 10)]}px`,
padding: `${[Math.floor(Math.random() * 10)]}px`,
transform: `rotate(${Math.floor(Math.random() * 90) - Math.floor(Math.random() * 90)}deg)`
})
}
// 指向
this.codeList = codeList
// 将当前数据派发出去
this.$emit('update:value', codeList.map(item => item.code).join(''))
},
getStyle (data) {
return `color: ${data.color}; font-size: ${data.fontSize}; padding: ${data.padding}; transform: ${data.transform}`
}
}
}
</script>
<style scoped >
.ValidCode{
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
span{
display: inline-block;
}
}
</style>
<template>部分
<template>
<div style="height: 100vh; display: flex;align-items: center;justify-content: center;background-color: #0f9876">
<div style="display: flex;background-color: white;width: 1150px;border-radius: 8px">
<div style="flex: 1">
<img src="@/assets/login.png" style="height: 600px;width: 100%">
</div>
<div style="flex: 1;display: flex;align-items: center;justify-content: center">
<el-form :model="user" :rules="rules" ref="loginRef">
<div style="font-size: 24px;font-weight: bold;display: flex;justify-content: center;margin-bottom: 30px">
欢迎登陆医疗管理系统
</div>
<el-form-item prop="username">
<el-input size="medium" v-model="user.username" placeholder="请输入用户名" prefix-icon="el-icon-user" style="width: 400px;"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input size="medium" show-password v-model="user.password" placeholder="请输入密码" prefix-icon="el-icon-lock" style="width: 400px"></el-input>
</el-form-item>
<el-form-item prop="code">
<div style="display: flex">
<el-input size="medium" v-model="user.code" placeholder="请输入验证码" prefix-icon="el-icon-circle-check" style="width: 200px"></el-input>
<div style="flex: 1;display: flex;align-items: center;justify-content: center;height: 36px;" >
<vaild-code v-on:update:value="getCode" v-model="user.code"></vaild-code>
</div>
</div>
</el-form-item>
<div style="display: flex">
<div style="flex: 1;margin-top: 10px;margin-bottom: 10px">还没有账号?请<span style="color: #42b983;cursor: pointer" @click="$router.push('/register')">注册</span></div>
<div style="flex: 1;text-align: right;margin-top: 10px;margin-bottom: 10px;color: #42b983"><span style="cursor: pointer">忘记密码</span></div>
</div>
<el-form-item>
<el-button v-on:click="login" style="color:white;background-color: #42b983;width: 100%">登 录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>部分
<script>
import VaildCode from "@/components/VaildCode.vue";
export default {
name:"Login",
components:{
VaildCode
},
data(){
//验证码校验
var validateCode = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入验证码'));
} else if (value.toLowerCase()!==this.code){
callback(new Error('验证码错误'));
}else{
callback()
}
};
return {
code: '', //验证码组件传来的code
user:{
code: '', //用户输入的code
username:'',
password:'',
},
rules:{
username: [
{required:true,message:'请输入用户名',trigger:'blur'},
],
password: [
{required:true,message:'请输入密码',trigger:'blur'},
],
code:[
{validator: validateCode, trigger: 'blur'},
]
}
}
},
methods:{
getCode(code) {
console.log(code)
//将验证码组件传过来的code赋值给Vue对象中自己设置的code
this.code = code.toLowerCase()
},
login(){
console.log(this.user.code)
this.$refs["loginRef"].validate((valid) => {
//验证通过
if (valid) {
//向后台发送请求并携带参数user,user中的username和password是和form表单进行绑定了的
axios.post('http://localhost:8082/user/login',this.user).then(res=>{
console.log(res)
//alert(res.data.msg)
if (res.data.code === '200'){
this.$message.success('登陆成功')
this.$router.push('/')
//将数据存放在localStorage中,并转换成json格式
localStorage.setItem('user',JSON.stringify(res.data.data))
}else {
this.$message.error(res.data.msg)
}
})
}
})
},
},
created() {
},
}
</script>
1.2.后端
后端程序只是简单的做了将输入的用户名和密码与数据库存放的进行了简单的比对,并将比对成功的用户id存放在了session中,mapper层和service层的代码就不展示了,只放controll-er层的代码
//登陆功能
@PostMapping("/login")
public Result login(@RequestBody User user, HttpServletRequest request){
User user1 = userMapper.selectUserByUsername(user);
if (!user.getPassword().equals(user1.getPassword())){
return Result.error("用户名或密码不正确");
}
//将id存入session
request.getSession().setAttribute("userId",user1.getId());
return Result.success();
}
效果演示
2.注册
注册功能和登录功能的程序逻辑是一样的,包含一个登录校验,两次密码必须要一致,程序如下:
<script>
import router from "@/router";
export default {
name:"Register",
data(){
//自定义的密码校验
var validatePassword = (rule, value, callback) => {
if (value === '') {
callback(new Error('请确认密码'));
} else if (value!==this.user.password){
callback(new Error('密码不一致'));
}else{
callback()
}
};
return {
user:{
name:'',
username:'',
password:'',
confirmPass:'',
},
rules:{
name: [
{required:true,message:'请输入姓名',trigger:'blur'},
],
username: [
{required:true,message:'请输入用户名',trigger:'blur'},
],
password: [
{required:true,message:'请输入密码',trigger:'blur'},
],
confirmPass:[
{validator: validatePassword, trigger: 'blur'},
],
}
}
},
methods:{
router() {
return router
},
register(){
this.$refs["registerRef"].validate((valid) => {
//验证通过
if (valid) {
//向后台发送请求并携带参数user,user中的username和password是和form表单进行绑定了的
axios.post('http://localhost:8082/user/register',this.user).then(res=>{
console.log(res)
//alert(res.data.msg)
if (res.data.code === '200'){
this.$message.success('注册成功')
this.$router.push('/login')
}else {
this.$message.error(res.data.msg)
}
})
}
})
},
},
created() {
},
}
</script>
<template>
<div style="height: 100vh; display: flex;align-items: center;justify-content: center;background-color: rgba(85,142,236,0.79)">
<div style="display: flex;background-color: white;width: 1150px;border-radius: 8px">
<div style="flex: 1">
<img src="@/assets/register.png" style="height: 600px;width: 100%">
</div>
<div style="flex: 1;display: flex;align-items: center;justify-content: center">
<el-form :model="user" :rules="rules" ref="registerRef">
<div style="font-size: 24px;font-weight: bold;display: flex;justify-content: center;margin-bottom: 30px">
欢迎注册医疗管理系统
</div>
<el-form-item prop="name">
<el-input size="medium" v-model="user.name" placeholder="请输入姓名" prefix-icon="el-icon-user" style="width: 400px;"></el-input>
</el-form-item>
<el-form-item prop="username">
<el-input size="medium" v-model="user.username" placeholder="请输入用户名" prefix-icon="el-icon-user" style="width: 400px;"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input size="medium" show-password v-model="user.password" placeholder="请输入密码" prefix-icon="el-icon-lock" style="width: 400px"></el-input>
</el-form-item>
<el-form-item prop="confirmPass">
<el-input size="medium" show-password v-model="user.confirmPass" placeholder="请确认密码" prefix-icon="el-icon-lock" style="width: 400px"></el-input>
</el-form-item>
<div style="display: flex">
<div style="flex: 1;margin-top: 10px;margin-bottom: 10px">已经有账号?请<span style="color: #558EECFF;cursor: pointer" @click="$router.push('/login')">登录</span></div>
</div>
<el-form-item>
<el-button v-on:click="register" style="color:white;background-color: rgb(85,142,236);width: 100%">注 册</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
在后台中稍微添加了一点验证,如果注册的用户名已经存在了,则会抛出异常,并将信息返回给前端
//注册功能
@PostMapping("/register")
public Result register(@RequestBody User user){
//先进行判断,这个用户名有没有重复
User username = userMapper.selectUserByUsername(user);
System.out.println("查到了:"+username);
if (username != null){
throw new ServiceException("用户名已存在");
}
int res = userMapper.addUser(user);
log.info("员工信息:{}",user.toString());
return Result.success("添加成功");
}
自定义异常类:
/**
* 自定义异常类
*/
public class ServiceException extends RuntimeException{
public ServiceException(String msg){
super(msg);
}
}
全局异常处理类:
/**
* 全局异常处理类
*/
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
public Result exceptionHandler(ServiceException e){
log.info(e.getMessage());
return Result.error(e.getMessage());
}
}
效果演示: