2025/4/15团队项目开发进度报告
一、完成登录功能,用户可以根据工号、用户名、电话号和邮箱登录;
登录页面(临时):

登录成功:

登录失败:

二、代码:
后端springboot:

common:
package com.example.demo.common;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CodeGenerator {
/**
* <p>
*
读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输⼊" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输⼊正确的" + tip + "!");
}
/**
*
操作步骤:
* 1.修改数据源包括地址密码信息,对应代码标记:⼀、 下同
* 2.模块配置,可以修改包名
* 3.修改模板(这步可忽略)
* @param args
*/
public static void main(String[] args) {
//代码⽣成器
AutoGenerator mpg = new AutoGenerator();
//全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/demo/src/main/java");
gc.setAuthor("qi");//作者名称
gc.setOpen(false);
gc.setSwagger2(true); //实体属性 Swagger2 注解
gc.setBaseResultMap(true);// XML ResultMap
gc.setBaseColumnList(true);// XML columList
//去掉service接⼝⾸字⺟的I, 如DO为User则叫UserService
gc.setServiceName("%sService");
mpg.setGlobalConfig(gc);
//数据源配置
//⼀、修改数据源
DataSourceConfig dsc = new DataSourceConfig();
//
dsc.setUrl("jdbc:mysql://localhost:3306/test314?useUnicode=true&characterEncoding=UTF8&useSSL=false");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("1234");
mpg.setDataSource(dsc);
//包配置
PackageConfig pc = new PackageConfig();
//pc.setModuleName(scanner("模块名"));
//⼆、模块配置
pc.setParent("com.example.demo")
.setEntity("entity")
.setMapper("mapper")
.setService("service")
.setServiceImpl("service.impl")
.setController("controller");
mpg.setPackageInfo(pc);
//⾃定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
//如果模板引擎是 freemarker
String templatePath = "templates/mapper.xml.ftl";
//如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
//⾃定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
//⾃定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
//⾃定义输出⽂件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发⽣变化!!
return projectPath + "/demo/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" +
StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType,
String filePath) {
//
判断⾃定义⽂件夹是否需要创建
checkDir("调⽤默认⽅法创建的⽬录,⾃定义⽬录⽤");
if (fileType == FileType.MAPPER) {
//
已经⽣成 mapper ⽂件判断存在,不想重新⽣成返回 false
return !new File(filePath).exists();
}
//
允许⽣成模板⽂件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
//配置模板
TemplateConfig templateConfig = new TemplateConfig();
//三、修改模板配置⾃定义输出模板
//指定⾃定义模板路径,注意不要带上.ftl/.vm, 会根据使⽤的模板引擎⾃动识别
//
/*templateConfig.setEntity("templates/entity2.java");
templateConfig.setService("templates/service2.java");
templateConfig.setController("templates/controller2.java");
templateConfig.setMapper("templates/mapper2.java");
templateConfig.setServiceImpl("templates/serviceimpl2.java");*/
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
//策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("你⾃⼰的⽗类实体,没有就不⽤设置!");
//strategy.setSuperEntityClass("BaseEntity");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
//公共⽗类
//strategy.setSuperControllerClass("BaseController");
// strategy.setSuperControllerClass("你⾃⼰的⽗类控制器,没有就不⽤设置!");
//写于⽗类中的公共字段
// strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英⽂逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
//strategy.setTablePrefix(pc.getModuleName() + "_");
//忽略表前缀tb_,⽐如说tb_user,直接映射成user对象
//四、注意是否要去掉表前缀
//strategy.setTablePrefix("tb_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
package com.example.demo.common;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CoreConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//是否发送Cookie
.allowCredentials(true)
//放⾏哪些原始域
.allowedOriginPatterns("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
package com.example.demo.common;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
package com.example.demo.common;
import lombok.Data;
import java.util.HashMap;
@Data
public class QueryPageParam {
//默认
private static int PAGE_SIZE = 20;
private static int PAGE_NUM = 1;
private int pageSize=PAGE_SIZE;
private int pageNum=PAGE_NUM;
private HashMap param=new HashMap();
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
@Override
public String toString() {
return "QueryPageParam{" +
"pageSize=" + pageSize +
", pageNum=" + pageNum +
", param=" + param +
'}';
}
public HashMap getParam() {
return param;
}
public void setParam(HashMap param) {
this.param = param;
}
}
package com.example.demo.common;
import lombok.Data;
@Data
public class Result {
private int code;//200 //400
private String msg;//:"成功、失败",
private Long total;//10
private Object data;
public static Result fail(String 参数不能为空){
return result(400,"失败",0L,null);
}
/*
* vivy
* 25/4/14
* fail
* */
public static Result fail(String code, String msg) {
Result result = new Result();
result.setCode(Integer.parseInt(code));
result.setMsg(msg);
return result;
}
public static Result success(Object data){
return result(200,"成功",0L,data);
}
public static Result success(){
return result(200,"成功",0L,null);
}
public static Result success(Object data,Long total){
return result(200,"成功",total,data);
}
public static Result result(int code, String msg, Long total, Object data) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
result.setTotal(total);
result.setData(data);
return result;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
controller:
package com.example.demo.controller;
import com.example.demo.common.Result;
import com.example.demo.dto.LoginRequest;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/*
* vivy
* 25/4/14
* 登录
* */
@PostMapping("/login")
public Result login(@RequestBody LoginRequest loginRequest) {
if (loginRequest.getAccount() == null || loginRequest.getPassword() == null) {
return Result.fail("账号和密码不能为空");
}
User user = userService.login(loginRequest);
if (user != null) {
// 不返回密码
user.setPassword(null);
return Result.success(user);
} else {
return Result.fail("账号或密码错误");
}
}
}
dto:
package com.example.demo.dto;
import lombok.Data;
/*
* vivy
* 25/4/14
* 登录
* */
@Data
public class LoginRequest {
private String account;
private String password;
}
entity:
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("users")
public class User {
@TableId
private String id;
private String username;
private String phone;
private String email;
private String password;
private String role;
}
exception:
package com.example.demo.exception;
/*
* vivy
* 25/4/14
* */
public class CustomException extends RuntimeException {
private String code;
private String msg;
public CustomException(String code, String msg){
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
package com.example.demo.exception;
import com.example.demo.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/*
* vivy
* 25/4/14
* */
@ControllerAdvice("com.demo.controller")
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody // 返回json串
public Result error(Exception e) {
e.printStackTrace();
return Result.fail(e.getMessage());
}
@ExceptionHandler(CustomException.class)
@ResponseBody // 返回json串
public Result error(CustomException e) {
return Result.fail(e.getCode(), e.getMsg());
}
}
mapper:
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
service:
package com.example.demo.service;
import com.example.demo.dto.LoginRequest;
import com.example.demo.entity.User;
public interface UserService {
/*
* vivy
* 25/4/14
* 登录
* */
User login(LoginRequest loginRequest);
}
service.Impl:
package com.example.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.dto.LoginRequest;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
/*
* vivy
* 25/4/14
* 登录
* */
@Override
public User login(LoginRequest loginRequest) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", loginRequest.getAccount())
.or().eq("phone", loginRequest.getAccount())
.or().eq("email", loginRequest.getAccount())
.or().eq("id", loginRequest.getAccount());
User user = userMapper.selectOne(queryWrapper);
if (user != null && user.getPassword().equals(loginRequest.getPassword())) {
// 实际项目中应该使用加密算法比较密码
return user;
}
return null;
}
}
前端Vue3:

api:
import request from '@/utils/request'
/*
* vivy
* 25/4/14
* 登录
* */
export function login(data) {
return request({
url: '/user/login',
method: 'post',
data
})
}
utils:
import axios from "axios";
import {ElMessage} from "element-plus";
const request = axios.create({
baseURL: "http://localhost:8090",
timeout: 30000//后台接口超时
})
//request拦截器
//可以自请求发送前对请求的设置
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
return config
},
error => {
return Promise.reject(error)
});
//response拦截器
//可以在接口响应后统一处理
request.interceptors.response.use(
response => {
let res = response.data;
if(typeof res==="string"){
res =res? JSON.parse(res):res
}
return res;
},
error => {
if(error.response.status===404){
ElMessage.error("未找到接口")
}else if(error.response.status===500){
ElMessage.error("系统异常请查看后端控制台报错")
}else{
ElMessage.error(error.message)
}
return Promise.reject(error)
}
)
export default request
views:
<!-- vivy -->
<!-- 05/4/14 -->
<template>
<div class="login-container">
<el-card class="login-card">
<h2 class="login-title">系统登录</h2>
<el-form :model="loginForm" :rules="loginRules" ref="loginFormRef">
<el-form-item prop="account">
<el-input
v-model="loginForm.account"
placeholder="工号/用户名/手机号/邮箱"
prefix-icon="User"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="密码"
prefix-icon="Lock"
show-password
/>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click="handleLogin" style="width: 100%">
登录
</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { login } from '@/api/user'
const router = useRouter()
const loading = ref(false)
const loginFormRef = ref(null)
const loginForm = reactive({
account: '',
password: ''
})
const loginRules = {
account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
}
const handleLogin = async () => {
if (!loginFormRef.value) return
await loginFormRef.value.validate(async (valid) => {
if (valid) {
loading.value = true
try {
const res = await login(loginForm)
if (res.code === 200) {
ElMessage.success('登录成功')
// 存储用户信息到本地存储
localStorage.setItem('userInfo', JSON.stringify(res.data))
// 跳转到首页
router.push('/manager/home')
} else {
ElMessage.error(res.msg || '登录失败')
}
} catch (error) {
console.error('登录错误:', error)
ElMessage.error('登录失败,请稍后重试')
} finally {
loading.value = false
}
}
})
}
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f7fa;
}
.login-card {
width: 400px;
}
.login-title {
text-align: center;
margin-bottom: 30px;
color: #409EFF;
}
</style>

浙公网安备 33010602011771号