一、项目简介
一共分为三个角色:管理员、用户、设计师
登录功能:账号+密码+身份选择,登录成功后跳转到各身份对应的页面
注册功能:只允许用户和设计师注册,用户可以直接注册成功,设计师提交材料后注册需要管理员审核成功后方可注册成功。
注册页面要求必填:
账号:用户自定义,注册成功后不可修改,同一个角色下账号不重复,不同角色账号可以重复。
二、注册
1.前端
先上目录文件:
(1)register.vue文件
template部分:
注 册
男女我是客户,我想装修房子我是设计师,我想设计装修将文件拖到此处,或点击上传请上传设计师相关材料验证,只能上传jpg/png文件,且不超过500kb提交
script部分:包含输入验证 表单提交功能
import VDistpicker from 'v-distpicker'export default {name: "Register",components: {VDistpicker},data() {return {form: {useraccount: '',userpsd: '',sex: '1',roleId: '1',address: '',province: '',city:'',area: '',},rules: {useraccount: [{required: true, message: "请输入账号", trigger: "blur"},{min: 1, max: 20, message: '请勿超过20个字符!', trigger: 'blur'},{validator: (rule, value, callback) => {const reg = /^[\u4E00-\u9FA5A-Za-z0-9]+$///正则表达式 只能输入英文、汉字与数字if (!reg.test(value)) {callback(new Error('请勿输入特殊字符'))} else {callback()}}}],userpsd: [{required: true, message: "请输入密码", trigger: "blur"},{min: 6, max: 16, message: '长度在 6 到 16个字符', trigger: 'blur'}],checkPass: [{required: true, message: "请再次输入密码", trigger: "blur"},{min: 6, max: 16, message: '长度在 6 到 16个字符', trigger: 'blur'},{validator: (rule, value, callback) => {if (value !== this.form.userpsd) {callback(new Error("两次输入密码不一致"));} else {callback()}}}]}, placeholders: {province: '请选择省份',city: '请选择市',area: '请选择区',},};},methods: {onChangeProv(province) {this.province=province.value;},onChangeCity(city) {this.city=city.value;},onChangeArea(area) {this.area=area.value;},// 首先限制它只能输入整数,最大长度为maxlength="11",其次是当它输入长度达到11位时进行校验onInput(key, event) {this.form[key] = event.replace(/[^\d]/g, '')if (event.length >= 11) {const reg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/if (!reg.test(event)) {console.log('您输入的手机号不正确')}}},submit() {//校验输入this.$refs.form.validate((valid)=>{if (valid){this.form.address=this.province+this.city+this.area;//包装地址 //注册功能this.$axios.post(this.$httpUrl + '/login/register', this.form).then(res => res.data).then(res => {console.log(res)//用户注册成功或设计师成功提交材料后,显示相关信息后自动返回首页if (res.code === 200) {if (this.form.roleId==1){alert("用户注册成功")window.location.href = "/Login";}else{alert("您的注册材料已提交,请等候管理员审批!")window.location.href = "/Index";}} else {alert("该账号已注册过!请重新输入")//注册失败,返回注册页面}})}else{alert("请按照规范输入账号")}})}}}
style部分:
.register-container {/*position: absolute;*/width: 100%;height: 100%;overflow: hidden; background-image: url("../assets/reg_background.jpg");background-size: 100% 100%;background-repeat: no-repeat;}.register-form {width: 600px;margin: 150px auto;background-color: rgb(214, 174, 218);padding: 30px;border-radius: 20px;}.title {text-align: center;font-family: 幼圆;}
(2)main.js文件
import Vuefrom 'vue';import Element from 'element-ui';import VueRouter from 'vue-router';import 'element-ui/lib/theme-chalk/index.css';import 'default-passive-events';import VDistpicker from 'v-distpicker'export default{component:{ VDistpicker }}import App from './App.vue'import axios from 'axios';import router from "./router/index.js";Vue.prototype.$axios=axios;//数据跨域Vue.prototype.$httpUrl='http://localhost:8090'Vue.config.devtools=trueVue.config.productionTip = falseVue.use(Element);Vue.use(VueRouter);new Vue({el:'#app',router,render: h => h(App),});
(3)index.js文件
主要设置router,实现页面之间的跳转
import VueRouter from 'vue-router'import Index from "../components/Index.vue";import DesignShow from "../components/user/DesignShow.vue";import EnterpriseShow from "@/components/user/EnterpriseShow";import DesignerShow from "@/components/user/DesignerShow";import Login from "@/components/Login";import Register from "@/components/Register";import AdminIndex from "@/components/admin/AdminIndex";import DesignerIndex from "@/components/designer/DesignerIndex";const routes=[{ path:'/Index', name:'Index', component:Index},{ path:'/DesignShow', name:'DesignShow', component:DesignShow},{ path:'/EnterpriseShow', name:'EnterpriseShow', component:EnterpriseShow},{ path:'/DesignerShow', name:'DesignerShow', component:DesignerShow},{ path:'/Login', name:'Login', component:Login},{ path:'/Register', name:'Register', component:Register},{ path:'/admin/Index', name:'adminIndex', component:AdminIndex},{ path:'/designer/Index', name:'designerIndex', component:DesignerIndex}]const router = new VueRouter({routes,mode: "history" //路由模式(默认为hash模式)})export default router
最终页面:
2. 后端:
我后端的端口是8090
目录结构
(1)LoginController.java文件
我注册和登录后端放在一个controller文件中了
package com.yjt.controller;import com.yjt.common.Result;import com.yjt.entity.User;import com.yjt.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController@CrossOrigin(origins = "*")//跨域设置@RequestMapping("/login")public class LoginController {@Autowiredprivate UserService userService;@PostMapping("/login")public Result login (@RequestBody User user){List userList1=userService.query().eq("useraccount",user.getUseraccount()).eq("role_id",user.getRoleId()).list();//查找账号是否已注册if (!userList1.isEmpty()){//账号注册过//查找账号密码是否匹配List userList2=userService.query().eq("useraccount",user.getUseraccount()).eq("userpsd",user.getUserpsd()).eq("role_id",user.getRoleId()).list();if(!userList2.isEmpty()){ //账号密码一致return Result.suc(user,0L);}else{return Result.fail(401);//code:401代表密码错误}}else{returnResult.fail(); //默认code400:代表账号未注册}}@PostMapping("/register")public Result register(@RequestBody User user) {int roleId = user.getRoleId();String account=user.getUseraccount();List userList=userService.query().eq("useraccount", account).eq("role_id",roleId).list();if (roleId == 1&& userList.isEmpty()) {//角色为用户且未注册过int id=userService.count();user.setUserid(id+1);userService.save(user);return Result.suc("用户注册成功",null,0L);} else if (roleId == 2&& userList.isEmpty()) {//角色为设计师且未注册过return Result.suc("您的注册材料已提交,请等候管理员审批!",user,0L);} else {return Result.fail();}}}
(2)user.java文件
package com.yjt.entity;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.annotation.TableField;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.EqualsAndHashCode;@Data@EqualsAndHashCode(callSuper = false)@ApiModel(value="User对象", description="")public class User {private static final long serialVersionUID = 1L;@TableId("Userid")private Integer userid;@TableField("Username")private String username;@TableField("Userpsd")private String userpsd;@TableField("Useraccount")private String useraccount;private Integer age;private Integer sex;private String phone;@TableField("role_id")private Integer roleId;@TableField("isValid")private String isvalid;private String address;}
(3)Result.java文件
package com.yjt.common;import lombok.Data;@Datapublic class Result {privateint code;private String msg;private Long total;private Object data;//失败public static Result fail(){return result(400,"Fail!",0L,null);}public static Result fail(int code){return result(code,"Fail!",0L,null);}//成功!public static Result suc(){return result(200,"成功Win!",0L,null);}public static Result suc(Object data){return result(200,"成功Win!",0L,data);}public static Result suc(Object data,Long total){return result(200,"成功Win!",total,data);}public static Result suc(String msg,Object data,Long total){return result(200,msg,total,data);}private static Result result(int code,String msg,Long total,Object data){Result result=new Result();result.setData(data);result.setMsg(msg);result.setCode(code);result.setTotal(total);return result;}}
(4)自动生成的usermapper接口
package com.yjt.mapper;import com.yjt.entity.User;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import org.apache.ibatis.annotations.Mapper;@Mapperpublic interface UserMapper extends BaseMapper {}
与UserMapper.xml
Userid, Username, Userpsd, Useraccount, age, sex, phone, role_id, isValid,address
(5)接口userService
package com.yjt.service;import com.yjt.entity.User;import com.baomidou.mybatisplus.extension.service.IService;public interface UserService extends IService {}
userServiceImpl
package com.yjt.service.impl;import com.yjt.entity.User;import com.yjt.mapper.UserMapper;import com.yjt.service.UserService;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl extends ServiceImpl implements UserService {}
(6)application.yml配置
server:port: 8090spring:datasource:url: jdbc:mysql://localhost:3306/wisehouse?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456
(7)CodeGenerate.java文件 这个是跟着老师敲的文件,具体有什么作用还没明白。。。。
package com.yjt.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;// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中public class CodeGenerator {/** * * 读取控制台内容 *
*/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 + "!");}public static void main(String[] args) {// 代码生成器AutoGenerator mpg = new AutoGenerator();// 全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir")+"/WiseHouse";gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("yjt");gc.setOpen(false);gc.setSwagger2(true); //实体属性 Swagger2 注解gc.setBaseResultMap(true);//XML ResultMapgc.setBaseColumnList(true);//XML columList//去掉service接口首字母的I,如DO为User则叫UserServicegc.setServiceName("%sService");mpg.setGlobalConfig(gc);// 数据源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://localhost:3306/wisehouse?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8");// dsc.setSchemaName("public");dsc.setDriverName("com.mysql.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("123456");mpg.setDataSource(dsc);// 包配置PackageConfig pc = new PackageConfig();//pc.setModuleName(scanner("模块名"));//二、模块配置pc.setParent("com.yjt").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}};// 如果模板引擎是 freemarkerString templatePath = "/templates/mapper.xml.ftl";// 如果模板引擎是 velocity// String templatePath = "/templates/mapper.xml.vm";// 自定义输出配置List focList = new ArrayList();// 自定义配置会被优先输出focList.add(new FileOutConfig(templatePath) {@Overridepublic String outputFile(TableInfo tableInfo) {// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;}});/*cfg.setFileCreate(new IFileCreate() {@Overridepublic boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {// 判断自定义文件夹是否需要创建checkDir("调用默认方法创建的目录,自定义目录用");if (fileType == FileType.MAPPER) {// 已经生成 mapper 文件判断存在,不想重新生成返回 falsereturn !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();// templateConfig.setController();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.setEntityLombokModel(true);strategy.setRestControllerStyle(true);// 公共父类//strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");// 写于父类中的公共字段strategy.setSuperEntityColumns("id");strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));strategy.setControllerMappingHyphenStyle(true);//strategy.setTablePrefix(pc.getModuleName() + "_");mpg.setStrategy(strategy);mpg.setTemplateEngine(new FreemarkerTemplateEngine());mpg.execute();}}
三、登录
前端:Login.vue文件
template部分:
登陆页面管理员用户设计师登录注册
script部分:
export default {name: "Login",data() {return {sizeForm: {useraccount: '',userpsd: '',delivery: false,roleId:'1',type: [],},rules: {useraccount: [{required: true, message: "请输入账号", trigger: "blur"},{validator: (rule, value, callback) => {const reg = /^[\u4E00-\u9FA5A-Za-z0-9]+$///正则表达式 只能输入英文、汉字与数字if (!reg.test(value)) {callback(new Error('请勿输入特殊字符'))} else {callback()}}}],userpsd:[{required: true, message: "请输入密码", trigger: "blur"},{ min: 6, max: 16, message: '长度在 6 到 16个字符', trigger: 'blur' }]}};},methods: {onSubmit() {//注册功能this.$axios.post(this.$httpUrl + '/login/login', this.sizeForm).then(res => res.data).then(res => {console.log(res)//登陆成功后,跳转到相应页面if (res.code === 200) {if (this.sizeForm.roleId==0){window.location.href = "admin/Index";}else if(this.sizeForm.roleId==1) {window.location.href = "/Index";}else{window.location.href = "designer/Index";}} else if(res.code === 400){alert("该账号未注册")//注册失败,返回注册页面}else{alert("密码错误")}})},register () {//指定跳转的地址this.$router.replace('/Register')}}}
style部分:
.LoginMes {text-align: center;color: #f3730a;font-family: 幼圆;font-size: 30px;margin-bottom: 20px;}.login-container {/*position: absolute;*/width: 100%;height: 100%;overflow: hidden;background-image: url("../assets/reg_background.jpg");background-size: 100% 100%;background-repeat: no-repeat;}.login-form {width: 480px;margin: 150px auto;background-color: rgb(143, 180, 229);padding: 50px;border-radius: 80px;}
最终页面:
先写到这里,具体方法实现原理等我有空了再继续写