前后端分离导航栏管理项目 发表于 2021-08-20 | 更新于 2021-09-17
| 字数总计: 5.1k | 阅读时长: 24分钟 | 阅读量:
前后端分离导航栏管理项目 这个项目其实我很早之前就已经想做了 之前的导航站 无后端 是基于yaml配置文件来配置
如图所示:点我查看该导航站
现在想给它加一个后台 并支持注册登录 自己定制管理自己导航站的链接 顺便巩固一下这
两个月的所学知识~
本系统是基于SpringBoot+Vue的前后端分离项目:可能用到的技术有
后端:SpringBoot MybatisPlus MySQL Redis Shiro
前端:Vue axios ElementUI
部署:Docker Linux
开发环境:IDEA DataGrip JDK1.8
后端接口开发(临时 ): 数据库设计 初始设定四张表:group(组表) links(链接表) user(用户表) roles(角色表)
sql文件 create table roles( id int auto_increment primary key, role_name varchar (256 ) not null comment '区分普通用户和管理员的' ) comment '角色表' ; create table user ( id int auto_increment, username varchar (256 ) not null , password varchar (256 ) not null , role_id int not null , constraint user_id_uindex unique (id), constraint user_roles_id_fk foreign key (role_id) references roles (id) ) comment '用户表' ; alter table user add primary key (id); create table `group `( id int auto_increment primary key, name varchar (256 ) null comment '组名' , user_id int not null comment '这个组属于哪个用户创建的' , constraint group_user_id_fk foreign key (user_id) references user (id) ) comment '分组的组名表' ; create table links( link varchar (256 ) not null comment '链接' , id int auto_increment primary key, icon varchar (256 ) null comment '网站logo链接' , name varchar (256 ) null comment '网站名称' , group_id int not null comment '组名外键' , user_id int not null comment '用户外键' , constraint links_user_id_fk foreign key (user_id) references user (id) ) comment '链接信息' ;
User实体类 package top.flya.index.entity;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import java.io.Serializable;import java.util.List;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class User implements Serializable { private static final long serialVersionUID = 1L ; @TableId(value = "id", type = IdType.AUTO) private Integer id; private String username; private String password; private Roles roles; private List<Group> groups; }
Roles实体类 package top.flya.index.entity;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import java.io.Serializable;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class Roles implements Serializable { private static final long serialVersionUID = 1L ; @TableId(value = "id", type = IdType.AUTO) private Integer id; private String roleName; }
Group 实体类 package top.flya.index.entity;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import java.io.Serializable;import java.util.List;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class Group implements Serializable { private static final long serialVersionUID = 1L ; @TableId(value = "id", type = IdType.AUTO) private Integer id; private String name; private List<Links> links; }
Links实体类 package top.flya.index.entity;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import java.io.Serializable;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class Links implements Serializable { private static final long serialVersionUID = 1L ; @TableId(value = "id", type = IdType.AUTO) private Integer id; private String icon; private String name; private String link; }
返回前端结果进行封装 package top.flya.index.utils;import lombok.Data;@Data public class Result { private String msg; private Object data; private String code; private static Result m = new Result(); public static Result succ (Object data) { m.setCode("666" ); m.setData(data); m.setMsg("操作成功" ); return m; } public static Result succ (String mess, Object data) { m.setCode("666" ); m.setData(data); m.setMsg(mess); return m; } public static Result fail (String mess) { m.setCode("404" ); m.setData(null ); m.setMsg(mess); return m; } public static Result fail (String mess, Object data) { m.setCode("404" ); m.setData(data); m.setMsg(mess); return m; } }
Mybatis多表查询 本系统设定一个超级管理员 可查看所有用户信息 并进行CRUD 所以需要用到多表查询 来查询所有用户的所有信息
关于多表查询 本人借鉴了该博客的方法 Mybatis多表联查
接口1:查询所有用户信息 Controller层
@Resource UserService userService; @GetMapping("/all") Result getAllUsers () { List<User> userList =userService.getAllUsers(); if (userList != null ) { return Result.succ("操作成功" ,userList); } return Result.fail("操作失败" ); }
Mapper文件
<resultMap id ="Users" type ="top.flya.index.entity.User" > <id column ="id" property ="id" /> <result column ="username" property ="username" /> <result column ="password" property ="password" /> <association property ="roles" javaType ="top.flya.index.entity.Roles" > <result column ="id" property ="id" /> <result column ="roleName" property ="roleName" /> </association > <collection property ="groups" ofType ="top.flya.index.entity.Group" > <result property ="id" column ="id" /> <result property ="name" column ="groupName" > </result > <collection property ="links" ofType ="top.flya.index.entity.Links" > <result property ="id" column ="id" /> <result property ="icon" column ="icon" /> <result property ="link" column ="link" /> <result property ="name" column ="name" /> </collection > </collection > </resultMap > <select id ="getAllUsersMessage" resultMap ="Users" > select u.id 'id',u.username 'username',u.password 'password',r.role_name 'roleName', l.icon 'icon',l.name 'name',l.link 'link',g.name 'groupName' from user as u ,links as l ,roles as r ,`group` as g where u.role_id =r.id and l.user_id=u.id and g.user_id =u.id and l.group_id =g.id </select >
接口测试效果
2021/8/31日改进代码 new1: 所有请求方式改为Post请求 接受参数统一封装成DTO 对象 new2: 去除所有非空判断以及字符串长度判断(不重复写无用代码) 用
@NotEmpty(message = "密码不能为空")
@Size(max = 10,min = 6,message = "密码长度必须在6-10个字符之间")
非空判断和 长度判断注解来代替 注:Controller层 参数上需要加注解 @Valid @RequestBody
new3: 让@NotEmpty不抛异常而是返回自定义的异常信息 捕捉@NotEmpty的异常, 捕捉到后, 获取到自定义的message信息, 然后返回给客户端
package top.flya.index.Exception;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import top.flya.index.utils.Result;@Slf4j @ControllerAdvice public class VaildExceptionConfig { @ResponseBody @ExceptionHandler(MethodArgumentNotValidException.class) public Result throwCustomException (MethodArgumentNotValidException methodArgumentNotValidException) { log.info("[ @Vaild异常捕获 ] " + methodArgumentNotValidException.getMessage()); return Result.fail(methodArgumentNotValidException.getBindingResult().getFieldError().getDefaultMessage()); } }
注册登录的DTO package top.flya.index.DTO;import lombok.Getter;import lombok.Setter;import lombok.ToString;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotEmpty;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;@Getter @Setter @ToString public class RegisterAndLoginDTO { @NotEmpty(message = "用户名不能为空") private String username; @NotEmpty(message = "密码不能为空") @Size(max = 10,min = 6,message = "密码长度必须在6-10个字符之间") private String password; }
接口2:注册接口 逻辑 : 判断该用户是否存在 不存在就可以注册 默认注册用户为普通用户
Controller
@GetMapping("/register") Result RegisterUser (@RequestParam("username") String userName, @RequestParam("password") String password) { if (userName!=null &&password!=null ){ Boolean existingUser=userService.existUser(userName); if (existingUser) { return Result.fail("该用户已存在,换一个名字吧~" ); } Boolean success = userService.registerUser(userName,password); if (success) { return Result.succ("注册成功" ); } return Result.fail("操作失败" ); } return Result.fail("请确认用户名密码是否已经输入!!" ); }
newController
(看起来简便了不少)
@PostMapping("/register") Result RegisterUser (@Valid @RequestBody RegisterAndLoginDTO rld) { Boolean existingUser=userService.existUser(rld.getUsername()); System.out.println(existingUser+"--->" ); if (existingUser) { return Result.fail("该用户已存在,换一个名字吧~" ); } Boolean success = userService.registerUser(rld.getUsername(),rld.getPassword()); if (success) { return Result.succ("注册成功" ); } return Result.fail("操作失败" ); }
Mapper
<insert id ="registerUser" > insert into user(username,password,role_id)values (#{username},#{password},2) </insert >
接口测试效果
接口3: 用户登录接口 登录逻辑: 输入用户名密码进行登录验证 先判断是否存在该用户 不存在提示注册
存在判断账号密码是否正确 账号密码信息正确之后获取该用户的所有信息备用
Controller
@GetMapping("/login") Result LoginUser (@RequestParam("username") String userName, @RequestParam("password") String password) { if (userName!=null &&password!=null ) { Boolean existingUser=userService.existUser(userName); if (!existingUser) { return Result.fail("该用户不存在,请注册后登陆" ); } Boolean success=userService.loginUser(userName,password); if (success) { User user=userService.getUserDetail(userName); return Result.succ("登陆成功" ,user); } return Result.fail("登陆失败,账号或密码错误" ); } return Result.fail("请确认用户名密码是否已经输入!!" ); }
newController
@PostMapping("/login") Result LoginUser (@Valid @RequestBody RegisterAndLoginDTO rld) { Boolean existingUser = userService.existUser(rld.getUsername()); if (!existingUser) { return Result.fail("该用户不存在,请注册后登陆" ); } Boolean success = userService.loginUser(rld.getUsername(), rld.getPassword()); if (success) { User user = userService.getUserDetail(rld.getUsername()); return Result.succ("登陆成功" , user); } return Result.fail("登陆失败,账号或密码错误" ); }
Mapper
<select id ="existUser" resultType ="top.flya.index.entity.User" > select * from user where username = #{username}; </select > <select id ="selectUser" resultType ="top.flya.index.entity.User" > select *from user where username = #{username} and password =#{password}; </select > <select id ="getUserByUserName" resultMap ="Users" > select u.id 'id',u.username 'username',u.password 'password',r.role_name 'roleName', l.icon 'icon',l.name 'name',l.link 'link',g.name 'groupName' from user as u ,links as l ,roles as r ,`group` as g where u.username=#{username} and u.role_id =r.id and l.user_id=u.id and g.user_id =u.id and l.group_id =g.id </select >
接口效果测试
修改密码的DTO package top.flya.index.DTO;import lombok.Getter;import lombok.Setter;import lombok.ToString;import javax.validation.constraints.NotEmpty;import javax.validation.constraints.Size;@Getter @Setter @ToString public class ChangePasswordDTO { @NotEmpty(message = "用户名不能为空") private String username; @NotEmpty(message = "密码不能为空") @Size(max = 10,min = 6,message = "密码必须为6-10间的数字或字母") private String newPassword; }
接口4:修改用户密码 修改密码逻辑:用户登录进去后台之后输入新密码即可修改 如果新密与老密相同则提示不可修改(也可联系超级管理员进行修改 后期添加手机号登录注册功能 可支持手机号接码改密)
Controller
@GetMapping("/changePassword") Result changePassword (@RequestParam("username") String userName,@RequestParam("newPassword") String newPassword) { System.out.println("用户名:" +userName+"--新密码:" +newPassword); if (userName!=null &&newPassword!=null ) { if (newPassword.equals(userMapper.getOldPassword(userName))) { return Result.fail("新密码不能与老密码相同!" ); } Boolean changed = userService.changePassword(userName,newPassword); if (changed) { return Result.succ("修改成功,您的新密码为:" +userService.getUserDetail(userName).getPassword()); } } return Result.fail("操作失败" ); }
newController
@PostMapping("/changePassword") Result changePassword (@Valid @RequestBody ChangePasswordDTO cpd) { System.out.println("用户名:" +cpd.getUsername()+"--新密码:" +cpd.getNewPassword()); if (cpd.getNewPassword().equals(userMapper.getOldPassword(cpd.getUsername()))) { return Result.fail("新密码不能与老密码相同!" ); } Boolean changed = userService.changePassword(cpd.getUsername(),cpd.getNewPassword()); if (changed) { return Result.succ("修改成功,您的新密码为:" +userService.getUserDetail(cpd.getUsername()).getPassword()); } return Result.fail("操作失败" ); }
Mapper
<update id ="changePassword" > update user set password=#{newPassword} where username=#{username} </update > <select id ="getOldPassword" resultType ="string" > select password from `user` where username=#{username} </select >
接口效果测试
接口5:修改组名 修改组名逻辑: 传入UserID、旧组名 新组名来修改
Controller
@PostMapping("/modifyGroup") Result modifyGroup (@Valid @RequestBody ModifyGroupDTO mgo) { boolean modified = userService.modifyGroupName(mgo.getUserId(),mgo.getGroupName(),mgo.getNewGroupName()); if (modified) { return Result.succ("修改成功~" ); } return Result.fail("修改组名失败!" ); }
Mapper
<update id ="modifyGroupName" > update `group` set name = #{newGroupName} where user_id =#{userId} and id= #{groupId} </update >
DTO
package top.flya.index.DTO;import lombok.Getter;import lombok.Setter;import lombok.ToString;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;@Getter @Setter @ToString public class ModifyGroupDTO { @NotNull(message="userId不能为空") private int userId; private String groupName; @Size(max = 20 ,message = "新组名最大长度不得超过20个字符串") private String newGroupName; }
接口效果测试
接口6:给用户添加组 添加组逻辑:判断用户传入组名是否为空 不为空则判断用户是否重复添加同一个组 校验都通过之后则可添加
Controller
@GetMapping("/addGroup") Result addGroup (@RequestParam("username") String userName,@RequestParam("newGroup") String newGroup) { System.out.println("username" +userName+"---newGroup" +newGroup); if (userName!=null &&newGroup!=null ) { int size=userService.getUserGroupsByUserName(userName).size(); System.out.println("当前用户拥有组的个数为" +size); List<Group> groups=userService.getUserGroupsByUserName(userName); for (int i=0 ;i<size;i++) { if (groups.get(i).getName().equals(newGroup)) { return Result.fail("操作失败,请勿重复添加~" ); } } Boolean add=userService.addGroup(userName,newGroup); if (add) { String []groupNames=new String[size+1 ]; for (int i=0 ;i<userService.getUserGroupsByUserName(userName).size();i++) { groupNames[i]=userService.getUserGroupsByUserName(userName).get(i).getName(); } return Result.succ("添加组成功---你当前所拥有的组为" , Arrays.toString(groupNames)); } } return Result.fail("操作失败" ); }
DTO
package top.flya.index.DTO;import lombok.Getter;import lombok.Setter;import lombok.ToString;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;@Getter @Setter @ToString public class ModifyGroupDTO { @NotNull(message="userId不能为空") private int userId; private String username; private String groupName; @Size(max = 20 ,message = "新组名最大长度不得超过20个字符串") private String newGroupName; }
newController
@PostMapping("/addGroup") Result addGroup (@Valid @RequestBody ModifyGroupDTO mgo) { System.out.println("username" +mgo.getUserId()+"---newGroup" +mgo.getNewGroupName()); int size=userService.getUserGroupsByUserName(mgo.getUsername()).size(); System.out.println("当前用户拥有组的个数为" +size); List<Group> groups=userService.getUserGroupsByUserName(mgo.getUsername()); for (int i=0 ;i<size;i++) { if (groups.get(i).getName().equals(mgo.getNewGroupName())) { return Result.fail("操作失败,请勿重复添加~" ); } } Boolean add=userService.addGroup(mgo.getUsername(),mgo.getNewGroupName()); if (add) { String []groupNames=new String[size+1 ]; for (int i=0 ;i<userService.getUserGroupsByUserName(mgo.getUsername()).size();i++) { groupNames[i]=userService.getUserGroupsByUserName(mgo.getUsername()).get(i).getName(); } return Result.succ("添加组成功---你当前所拥有的组为" , Arrays.toString(groupNames)); } return Result.fail("操作失败" ); }
ServiceImpl
@Override public Boolean addGroup (String userName, String newGroup) { int userId = userMapper.getUserByUserName(userName).getId(); int added=userMapper.addGroup(userId,newGroup); if (added!=0 ) { return true ; } return false ; } @Override public List<Group> getUserGroupsByUserName (String userName) { if (userMapper.getUserGroupsByUserName(userName)!=null ) { return userMapper.getUserGroupsByUserName(userName); } return null ; }
Mapper
<select id ="getUserGroupsByUserName" resultType ="top.flya.index.entity.Group" > select `group`.name `name` from `group`,user where user.username=#{username} and `group`.user_id=user.id; </select > <insert id ="addGroup" > insert into `group`(`group`.name,`group`.user_id) values(#{newGroup},#{userId}) </insert >
接口效果测试
接口7:给组添加链接 添加链接逻辑: 首先根据用户传入的用户名(后期可优化为传用户id)查出用户id 然后根据用户id和组名查出用户组id 最后根据组id和用户id定位到需要插入链接的位置插入即可
如果链接存在则提示添加失败 链接重复(一个链接名对应多个链接 这很河里 但是链接不能重复)
Controller
@GetMapping("/addLink") Result addLink (@RequestParam("username") String userName,@RequestParam("groupName") String groupName ,@RequestParam("linkName") String linkName,@RequestParam("linkIcon") String linkIcon ,@RequestParam("link") String link) { if (userName!=null &&groupName!=null &&linkName!=null &&linkIcon!=null &&link!=null ) { int userId = userService.getUserDetail(userName).getId(); int groupId=userService.getGroupIdByUserIdAndGroupName(userId,groupName); boolean distinctLink=userService.getLinkByUserId(userId,link); if (distinctLink) { return Result.fail("该链接已存在不可重复添加!!" ); } boolean added=userService.addLinkByUserIdAndGroupId(userId,groupId,linkName,linkIcon,link); if (added) { return Result.succ("添加成功!" ); } } return Result.fail("添加失败" ); }
ServiceImpl
@Override public boolean getLinkByUserId (int userId, String link) { List<Links> linkList=userMapper.selectLinkList(userId); for (int i=0 ;i<linkList.size();i++) { if (link.equals(linkList.get(i).getLink())) { return true ; } } return false ; }
Mapper
<insert id ="addLinkByUserIdAndGroupId" > insert into links(link, icon, `name`, group_id, user_id)values(#{link},#{linkIcon},#{linkName},#{groupId},#{userId}) </insert > <select id ="selectLinkList" resultType ="top.flya.index.entity.Links" > select * from links where user_id=#{userId} </select > <select id ="getGroupIdByUserIdAndGroupName" resultType ="int" > select distinct `group`.id from `group` where `group`.user_id=#{userId} and `group`.name=#{groupName}; </select >
接口效果测试
接口8:移动链接到另一个组 移动链接逻辑:传入用户id 链接名 然后定位到该链接 并修改该链接对应的组id
Controller
@GetMapping("/moveLink") Result moveLink (@RequestParam("userId") int userId,@RequestParam("linkName") String linkName, @RequestParam("groupId") int groupId) { if (userId!=0 &&linkName!=null &groupId!=0 ) { Boolean move = userService.moveLink(userId,linkName,groupId); if (move) { return Result.succ("移动成功!" ); } } return Result.fail("移动失败" ); }
Mapper.xml
<update id ="moveLink" > update links set group_id=#{groupId} where user_id =#{userId} and name =#{linkName}; </update >
接口效果测试
接口9:删除链接 删除链接逻辑:根据用户id和链接名来唯一定位id并删除
Controller
@GetMapping("/deleteLink") Result deleteLink (@RequestParam("userId") int userId,@RequestParam("linkName") String linkName) { if (userId!=0 &&linkName!=null ) { int delete=userMapper.deleteLink(userId,linkName); if (delete!=0 ) { return Result.succ("删除成功" ); } } return Result.fail("删除失败" ); }
Mapper
<delete id ="deleteLink" > delete from links where user_id =#{userId} and name =#{linkName}; </delete >
接口效果测试
接口10:修改链接信息 修改链接逻辑:传入用户id 链接名来定位链接并修改链接信息
Controller
@GetMapping("/modifyLink") Result modifyLink (@RequestParam("userId") Integer userId, @RequestParam("linkName") String linkName, @RequestParam("newLinkName") String newLinkName, @RequestParam("newLinkIcon") String newLinkIcon, @RequestParam("newLink") String newLink) { if (userId!=null &&linkName!=null &&newLinkName!=null &&newLinkIcon!=null &&newLink!=null ) { Boolean modified = userService.modifyLink(userId,linkName,newLinkName,newLinkIcon,newLink); if (modified) { return Result.succ("修改成功" ); } } return Result.fail("修改失败" ); }
Mapper
<update id ="modifyLink" > update links set links.name=#{newLinkName},links.icon=#{newLinkIcon},links.link=#{newLink} where user_id=#{userId} and links.name=#{linkName} </update >
接口测试效果