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>
posted @ 2025-04-15 19:37  三拍  阅读(25)  评论(0)    收藏  举报