实战11:SpringBoot和Vue实现登录、注册和异常处理
目录
3、个人信息:卡片和表单 、localStorage存储登录用户全局用户数据 、根据用户名称获取用户数据 、修改用户数据
一、异常统一处理类
1、Result包装类
package com.example.demo.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*
接口统一返回包装类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private String code;
private String msg;
private Object data;
public static Result success() {
return new Result(Constants.CODE_200, "", null);
}
public static Result success(Object data) {
return new Result(Constants.CODE_200, "", data);
}
public static Result error(String code, String msg) {
return new Result(code, msg, null);
}
public static Result error() {
return new Result(Constants.CODE_500, "系统错误", null);
}
}
2、系统异常统一处理
1)业务异常类
package com.example.demo.exception;
import lombok.Getter;
/**
* 自定义异常
*/
@Getter
public class ServiceException extends RuntimeException {
private String code;
public ServiceException(String code, String msg) {
super(msg);
this.code = code;
}
}
2)统一异常处理
package com.example.demo.exception;
import com.example.demo.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.xml.ws.Response;
@RestControllerAdvice
public class GlobleExceptionHandler {
@ResponseBody
@ExceptionHandler(ServiceException.class)
public Result handle(ServiceException se){
return Result.error(se.getCode(),se.getMessage());
}
}
接口常量
package com.example.demo.common;
public interface Constants {
String CODE_200 = "200";
String CODE_401 = "401";//权限不足
String CODE_400 = "400";//参数错误
String CODE_500 = "500";
String CODE_600 = "600";
}
二、SpringBoot实现登录、注册、个人信息
@PostMapping("/login")
public Result login(@RequestBody UserDto userDto){
String username = userDto.getUsername();
String password = userDto.getPassword();
if (StrUtil.isBlank(username)||StrUtil.isBlank(password)){
return Result.error(Constants.CODE_400,"参数错误");
}
return Result.success(userService.login(userDto));
}
public Result register(@RequestBody UserDto userDto) {
String username = userDto.getUsername();
String password = userDto.getPassword();
if (StrUtil.isBlank(username)||StrUtil.isBlank(password)){
return Result.error(Constants.CODE_400,"参数错误");
}
return Result.success(userService.register(userDto));
}
@GetMapping("/username/{username}")
public Result findOne(@PathVariable String username){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
return Result.success(userService.getOne(queryWrapper));
}
package com.example.demo.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.common.Constants;
import com.example.demo.dto.UserDto;
import com.example.demo.entity.User;
import com.example.demo.exception.ServiceException;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author cizhu
* @since 2023-11-12
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Override
public UserDto login(UserDto userDto) {
User one = getUserInfo(userDto);
if (one != null) {
BeanUtil.copyProperties(one, userDto, true); //
return userDto;
} else {
throw new ServiceException(Constants.CODE_600, "用户名或密码错误"); //自定义异常
}
}
// List<User> list = list(queryWrapper);
// return list.size()!=0 ;
// }
@Override
public User register(UserDto userDto) {
User one = getUserInfo(userDto);
if (one == null) {
one = new User();
BeanUtil.copyProperties(userDto, one, true);
save(one);
} else {
throw new ServiceException(Constants.CODE_600, "用户已存在");
}
return one;
}
private User getUserInfo(UserDto userDto) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", userDto.getUsername());
queryWrapper.eq("password", userDto.getPassword());
User one;
try {
one = getOne(queryWrapper);
} catch (Exception e) {
throw new ServiceException(Constants.CODE_500, "系统异常"); //自定义异常
}
return one;
}
}
package com.example.demo.service;
import com.example.demo.dto.UserDto;
import com.example.demo.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author cizhu
* @since 2023-11-12
*/
public interface IUserService extends IService<User> {
UserDto login(UserDto userDto);
User register(UserDto userDto);
}
三、Vue实现登录、注册、个人信息
1、登录: 登录方法 、表单数据校验、登录表单、跳转注册
<template>
<div class="wrapper">
<div style="margin: 200px auto;background-color: #fff; width: 350px; padding: 20px; border-radius: 10px;">
<div style="margin: 20px 0;text-align: center; font-size: 24px;"><b>登录</b></div>
<el-form :rules="rules" :model="user" ref="userform">
<el-form-item prop="username">
<el-input size="medium" style="margin:10px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input size="medium" style="margin:10px 0" prefix-icon="el-icon-lock" show-password
v-model="user.password"></el-input>
</el-form-item>
<el-form-item style="margin: 10px 0; text-align: right">
<el-button type="primary" size="small" autocomplete="off" @click="login">登录</el-button>
<el-button type="warning" size="small" autocomplete="off" @click="$router.push('/register')">注册</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
user: {},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 10, message: '长度在 3 到 10个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20个字符', trigger: 'blur' }
]
}
}
},
methods: {
login() {
this.$refs['userform'].validate((valid) => {
if (valid) {
this.request.post("user/login", this.user).then(res => {
if (res.code === '200') {
localStorage.setItem("user",JSON.stringify(res.data))
this.$router.push("/")
this.$message.success("登录成功")
} else {
this.$message.error(res.msg);
}
})
}
});
},
}
}
</script>
<style>
.wrapper {
height: 100vh;
background-image: linear-gradient(to bottom right, #FC4668, #3F5EFB);
overflow: hidden;
}
</style>
2、注册:页面布局、表单数据校验 、注册 、返回登录
<template>
<div class="wrapper">
<div style="margin: 100px auto;background-color: #fff; width: 350px; padding: 20px; border-radius: 10px;height: 400px;">
<div style="margin: 20px 0;text-align: center; font-size: 24px;"><b>注册</b></div>
<el-form :rules="rules" :model="user" ref="userform">
<el-form-item prop="username">
<el-input placeholder="输入账号" size="medium" style="margin:5px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input placeholder="输入密码" size="medium" style="margin:5px 0" prefix-icon="el-icon-lock" show-password
v-model="user.password"></el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input placeholder="输入确认密码" size="medium" style="margin:5px 0" prefix-icon="el-icon-lock" show-password
v-model="user.confirmPassword"></el-input>
</el-form-item>
<el-form-item style="margin: 10px 0; text-align: right">
<el-button type="primary" size="small" autocomplete="off" @click="register">注册</el-button>
<el-button type="warning" size="small" autocomplete="off" @click="$router.push('/login')">返回登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data() {
return {
user: {},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 3, max: 10, message: '长度在 3 到 10个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20个字符', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20个字符', trigger: 'blur' }
]
}
}
},
methods: {
register() {
this.$refs['userform'].validate((valid) => {
if (valid) {
if (this.user.password!=this.user.confirmPassword) {
this.$message.error("两次输入密码不一致")
return false
} else {
}
this.request.post("user/register", this.user).then(res => {
if (res.code === '200') {
this.$message.success("注册成功")
} else {
this.$message.error(res.msg);
}
})
}
});
},
}
}
</script>
<style>
.wrapper {
height: 100vh;
background-image: linear-gradient(to bottom right, #FC4668, #3F5EFB);
overflow: hidden;
}
</style>
3、个人信息:卡片和表单 、localStorage存储登录用户全局用户数据 、根据用户名称获取用户数据 、修改用户数据
<template>
<el-card style="width: 500px">
<el-form label-width = "80px" size = "small">
<el-form-item label="用户名">
<el-input v-model="form.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="昵称">
<el-input v-model="form.nickname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="电话">
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="save">确 定</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
export default{
name: "Person",
data(){
return{
form:{},
user:localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")):{}
}
},
created(){
this.request.get("/user/username/"+this.user.username).then(res=>{
if (res.code == '200') {
this.form =res.data
}
})
},
methods:{
save() {
this.request.post("/user", this.form).then(res => {
if (res.data) {
this.$message.success("保存成功");
}else {
this.$message.error("保存失败");
}
});
},
}
}
</script>
<style>
</style>
4、路由配置
{
path: '/',
name: 'Manage',
redirect: '/home',
component: () => import('../views/Manage.vue'),
children: [
{path: 'home',name: '首页',component: ()=>import ('../views/Home.vue') },
{path: 'user',name: '用户管理',component: ()=>import ('../views/User.vue') },
{path: 'person',name: '个人信息',component: ()=>import ('../views/Person.vue') }
]
},
{
path: '/login',
name: 'Login',
component: () => import( '../views/Login.vue')
},
{
path: '/register',
name: 'Register',
component: () => import( '../views/Register.vue')
}
5、用户全局状态
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
currentPathName:''
},
mutations:{
setPath(state){
state.currentPathName= localStorage.getItem("currentPathName")
}
}
})
export default store