失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 电脑商城项目总结-01用户管理模块(注册 登录 修改密码 个人信息 上传头像)

电脑商城项目总结-01用户管理模块(注册 登录 修改密码 个人信息 上传头像)

时间:2023-03-07 00:04:21

相关推荐

电脑商城项目总结-01用户管理模块(注册 登录 修改密码 个人信息 上传头像)

目录

部分图片展示

application.properties

创建数据库并且验证是否静态资源能够正常访问

创建用户表

实体类

持久层

业务层

控制层

拦截器

单元测试

部分图片展示

以下是大体上的代码

application.properties

首先我们先在application.properties中配置好数据库的连接以及mapper的位置(就是dao对应的mybatis文件)

spring.datasource.url=jdbc:mysql://localhost:3306/store?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaispring.datasource.username=Wuyuhangspring.datasource.password=2002514wyh11mybatis.mapper-locations=classpath:mapper/*.xmlspring.servlet.multipart.max-file-size=10MBspring.servlet.multipart.max-request-size=15MB

创建数据库并且验证是否静态资源能够正常访问

静态资源都放在static目录下,这是默认好的(可以通过实现webMvcConfigurer进行配置路径,或者通过yaml);

访问路径的话:就是static往下(static相当于根)

创建用户表

最下面那四个是基础字段——>我们将其放到基类中;

盐值:加密——>方便后续的修改密码;

isDelete:验证是否被删除,因为你可能操作的时候被管理员删了;

实体类

package puterstore.entity;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;/*** @author diao /3/20*/@Data@AllArgsConstructor@NoArgsConstructorpublic class User extends BaseEntity implements Serializable {/*这里我们都用包装类,因为他里面有一些api方法,方便之后的业务逻辑* */private Integer uid ;private String username;private String password;private String salt;private String phone;private String email;private Integer gender;private String avatar;private Integer isDelete;}

基类:

package puterstore.entity;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;import java.util.Date;import java.util.Objects;/*** @author diao /3/20*/@Data@AllArgsConstructor@NoArgsConstructorpublic class BaseEntity implements Serializable {private String createdUser;private Date createdTime;private String modifiedUser;private Date modifiedTime;}

持久层

首先规划最底层的功能——>dao接口,然后再mybatis中写对应的sql

package puterstore.mapper;import puterstore.entity.User;import org.apache.ibatis.annotations.Param;import java.util.Date;/*** @author diao /3/20*//*用户模块持久层接口*/public interface UserMapper {//这里用包装类可以利用它的api进行业务判断:比如根据插入条数判断成功之类的/*** 插入用户的数据* @param user 用户的数据* @return 受影响的行数(增删改影响的行数作为返回值,根据返回值进行判断是否成功)*/Integer insert(User user);/*** 根据用户名查询用户数据* @param username 用户名* @return 如果找到对应用户就返回这个用户数据,否则返回null值*/User findByUsername(String username);/*** 根据uid来修改用户密码* @param uid* @param password:用户输入的新密码* @param modifiedUser:修改的执行者* @param modifiedTime:修改数据的时间* @return*/Integer updatePasswordByUid(@Param("uid") Integer uid,@Param("password") String password,@Param("modifiedUser") String modifiedUser,@Param("modifiedTime") Date modifiedTime);/*** 更改密码首先要判断该用户是否存在,不排除管理员误删的情况* @param uid 用户id* @return 返回对象*/User findByUid(Integer uid);/*** 更改用户信息* @param user:user对象(用户数据)* @return:返回整数条数*/Integer updateInfoByUid(User user);/*** @Param("SQL映射文件#{}占位符的变量名")* 和映射的接口的参数名不一致时,需要将某个参数强行注入到门口个占位符变量上* 根据用户的uid值修改用户头像* @param uid* @param avatar* @param modifiedUser* @param modifiedTime* @return*/Integer updateAvatarByUid(@Param("uid") Integer uid,@Param("avatar") String avatar,@Param("modifiedUser") String modifiedUser,@Param("modifiedTime") Date modifiedTime);}

对应的mapper.xml

提一嘴,mybatis利用的是两步映射——>1.一个namespace指定接口,通过接口利用JDK动态代理实现代理类的作用并将其加载到容器中 ;2.还一个id来指定方法名

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd"><!--namespace:用于指定当前映射文件与那个接口进行映射,需要指定接口的文件路径--><mapper namespace="puterstore.mapper.UserMapper"><!-- 自定义映射规则 id:表示给映射规则唯一个id值;type:表示数据库中的查询结果与Java中的哪个实体类进行结果集映射 --><resultMap id="UserEntityMap" type="puterstore.entity.User"><!--将表中与类中属性不一样的字段进行匹配指定,名称一样可以不写在定义映射规则时,主键是不可省略的,否则这条记录就不会被储存,就会被释放掉--><id column="uid" property="uid"></id><result column="is_delete" property="isDelete"></result><result column="created_user" property="createdUser"></result><result column="created_time" property="createdTime"></result><result column="modified_user" property="modifiedUser"></result><result column="modified_time" property="modifiedTime"></result></resultMap><!-- id:表示映射接口方法的名称,可以直接在标签的内容部来编写SQL语句 --><insert id="insert" useGeneratedKeys="true" keyProperty="uid">insert into t_user(username, password, salt, phone,email, gender, avatar, is_delete,created_user, created_time,modified_user, modified_time)values (#{username}, #{password}, #{salt}, #{phone},#{email}, #{gender}, #{avatar}, #{isDelete},#{createdUser}, #{createdTime}, #{modifiedUser}, #{modifiedTime})</insert><!-- select语句在执行时查询的结果是一个/多个对象resultType:表示查询的结果集类型,只需要指定对应的映射类的类型resultMap:当表的字段名和类的对象属性字段名不一致时,用来指定映射规则的--><select id="findByUsername" resultMap="UserEntityMap">select * from t_user where username= #{username}</select><!-- 根据uid设置密码和更新的用户以及时间 --><update id="updatePasswordByUid">update t_user setpassword=#{password},modified_user=#{modifiedUser},modified_time=#{modifiedTime}where uid=#{uid}</update><!-- 根据uid查询用户,看用户是否存在 --><select id="findByUid" resultMap="UserEntityMap">select * from t_user where uid=#{uid}</select><!-- 资料修改 --><update id="updateInfoByUid">update t_userset-- if表示条件标签,test接收的是一个boolean判断条件<if test="phone!=null">phone=#{phone},</if><if test="email!=null">email=#{email},</if><if test="gender!=null">gender=#{gender},</if>modified_user=#{modifiedUser},modified_time=#{modifiedTime}whereuid=#{uid}</update><!-- 根据uid设置头像avatar修改用户以及修改时间 --><update id="updateAvatarByUid">update t_usersetavatar=#{avatar},modified_user=#{modifiedUser},modified_time=#{modifiedTime}whereuid=#{uid}</update></mapper>

项目中的接口位置需要设定——>我们可以在Application类中利用@MapperScan()来设定

业务层

建议的标准建包形式:

1.首先先写业务接口IUserService——>规范大体的业务方法

package puterstore.service;import puterstore.entity.User;/*** @author diao /3/22*//*用户模块业务层接口*/public interface IUserService {/*** 定义一个user类型的操作列表:用户注册方法* @param user 用户的数据对象,参数是根据底层dao来的*/void reg(User user);/*** 登录功能* @param username* @param password* @return 返回一个User对象,因为我们登录之后,页面会有用户信息,比如右上角那种* 所以我们在登录成功之后要把当前用户数据以用户对象的形式进行返回* 状态管理:我们可以将数据保存在cookie或者session中,可以减少代码冗余* 避免重复很高的数据进行频繁的数据操作(比如说登录之后买东西还对数据库进行查询看你地理位置对不对之类的)* 一些常用的数据已经保存起来*/User login(String username,String password);/*** 修改密码* @param uid* @param username* @param oldPassword* @param newPassword*/void changePassword(Integer uid,String username,String oldPassword,String newPassword);/*** 获取当前登录的用户信息* @param uid* @return 返回当前用户信息展示到页面表单中* 声明一下,其实在我们登录之后,可以将用户信息放入到session中进行调用* 也可以获取我们需要的信息展示出来,但是session过期了就另外一码事了* 问题又来了,过期了不直接重新登录嘛*/User getByUid(Integer uid);/*** 修改用户资料* @param uid 当前登录的用户id:uid和username都是可以从session中获取* 在你登录的时候,uid和username就在session中* @param username 当前登录的用户名* @param user 修改用户对象:接收客户端个人资料能够提交的数据(用户phone,性别...)*/void changeInfo(Integer uid,String username,User user);/*** 修改用户头像* @param uid 用户id* @param avatar 用户头像路径* @param username 用户名称*/void changeAvatar(Integer uid,String avatar,String username);}

2.业务实现类——>需要根据具体需求定义异常出现的可能

实现业务接口,调用mapper中的方法(mapper与mybatis进行一个映射)

具体异常出现——>一般也就是增删改查中,比如insert时候,会发现用户已经存在了,所以要先利用查询方法然后进行判断,还有修改数据也是——>首先得判断是否有数据吧;等等...

package puterstore.service.impl;import puterstore.entity.User;import puterstore.mapper.UserMapper;import puterstore.service.IUserService;import puterstore.service.ex.*;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.util.DigestUtils;import java.util.Date;import java.util.UUID;/*** @author diao /3/22*//*用户模块业务层的实现类*/@Service//将当前累的对象交给Spring来管理public class UserServiceImpl implements IUserService {//调用底层mapper实现user插入@Autowiredprivate UserMapper userMapper;/*** 注册功能* @param user 用户的数据对象,参数是根据底层dao来的*/@Overridepublic void reg(User user) {//1、先通过传过来的user参数获取usernameString username = user.getUsername();//2、通过底层接口方法findByUsername判断用户是否被注册过User result = userMapper.findByUsername(username);//3.判断是否为nullif(result!=null){//说明注册过了,抛出用户名占用异常throw new UsernameDuplicatedException("用户名被占用");}String oldPassword = user.getPassword();//将密码和盐值作为一个整体作为一个整体进行加密String salt = UUID.randomUUID().toString().toUpperCase();//补全数据:盐值的记录( 因为每次调用这个方法,salt是不一样的),// 方便登录,因为你登录的话密码验证只能验证加密后的密码,而盐值又是随机的,所以得保存user.setSalt(salt);//将获取的老密码以及盐值封装到MD5加密方法中,并且将新密码设置到用户user中String md5Password = getMD5Password(oldPassword, salt);user.setPassword(md5Password);//补全的数据:is_delete 设置为0,不删除,说明不会对用户进行拦截user.setIsDelete(0);// 补全数据:4个日志字段user.setCreatedUser(user.getUsername());user.setModifiedUser(user.getUsername());Date date = new Date();user.setCreatedTime(date);user.setModifiedTime(date);//4、为null,说明没有被注册过,我们将用户插入Integer rows = userMapper.insert(user);if(rows!=1){throw new InsertException("插入用户信息发生异常");}}/**** @param username:先验证用户名,如果不存在就抛出异常* @param password:验证密码:1.先从数据库中取得老密码,和盐值* 2.盐值和输入的密码进行MD5加密,最后再与数据库中的老密码进行比对* @return*/@Overridepublic User login(String username, String password) {//1.根据用户名称查询用户数据是否存在,不存在抛出UserNotFoundExceptionUser result = userMapper.findByUsername(username);if(result==null){throw new UserNotFoundException("用户名不存在");}//2.检测密码是否匹配:得到数据库中的老密码String oldPassword = result.getPassword();String salt = result.getSalt();//将输入密码与用户盐值进行相同规则MD5加密String newMD5Password = getMD5Password(password, salt);//进行比对if(!newMD5Password.equals(oldPassword)){throw new PasswordNotMatchException("用户密码错误");}//3.判断is_delete字段是否为1标记已被删除if(result.getIsDelete()==1){throw new UserNotFoundException("用户数据不存在");}//4.调用mapper中的查询方法,这里我们进行数据压缩(user里面数据太多了,我们只要需要的几个)User user = new User();user.setUid(result.getUid());user.setUsername(result.getUsername());//返回有用户的头像,只要你一登录将avatar信息放入cookie中user.setAvatar(result.getAvatar());//6.返回已经封装好的User信息return user;}/**** @param uid:用户id* @param username:用户名* @param oldPassword:用户输入的老密码(原密码)* @param newPassword:用户输入的新密码*/@Overridepublic void changePassword(Integer uid, String username, String oldPassword, String newPassword) {User result = userMapper.findByUid(uid);//判断是否有用户if(result==null||result.getIsDelete()==1){throw new UserNotFoundException("用户数据不存在");}//将用户输入的老密码与数据库中的盐值进行加密与数据库中的实际老密码进行比较String md5Password = getMD5Password(oldPassword, result.getSalt());if (!result.getPassword().equals(md5Password)){throw new PasswordNotMatchException("密码错误");}//将新的密码设置到数据库中,将新的密码进行加密再去更新String newMd5Password = getMD5Password(newPassword, result.getSalt());Integer rows = userMapper.updatePasswordByUid(uid, newMd5Password, username, new Date());if(rows!=1){throw new UpdateException("更新数据时产生异常");}}/*** 通过uid获取用户信息* @param uid* @return 返回用户信息(个人资料所需要的用户信息)*/@Overridepublic User getByUid(Integer uid) {User result = userMapper.findByUid(uid);//对用户信息进行判断,可能出现异常if(result==null){throw new UserNotFoundException("用户数据不存在");}if(result.getIsDelete()==1){//可能出现用户被管理员删的情况throw new UserNotFoundException("用户不存在");}//然后我们将个人资料的信息封装到新的User对象中,传输需要的数据通过ajax显示前端上User user = new User();user.setUsername(result.getUsername());user.setPhone(result.getPhone());user.setEmail(result.getEmail());user.setGender(result.getGender());return user;}/**** @param uid 当前登录的用户id* @param username 当前登录的用户名* @param user 当前用户的新的个人资料数据+时间、修改用户以及uid*/@Overridepublic void changeInfo(Integer uid, String username, User user) {//调用findByUid()方法,根据Uid查询具体的用户数据(个人资料数据)User result = userMapper.findByUid(uid);//对数据进行判断,因为你修改是按钮触碰才会发生事件,所以说可能数据已经显示出来了//但是你修改确定之后发现原来的数据被管理员删除了,所以这里还需要判断if(result==null){throw new UserNotFoundException("用户数据不存在");}if(result.getIsDelete().equals(1)){throw new UserNotFoundException("用户数据不存在");}//向参数user中补全数据:修改时间,修改的人以及uiduser.setUid(uid);user.setModifiedUser(username);user.setModifiedTime(new Date());//用updateInfoByUid(User user)方法进行修改Integer rows = userMapper.updateInfoByUid(user);//可能修改数据时候出现异常if(rows!=1){throw new UpdateException("更新用户数据时出现未知错误,请联系系统管理员");}}@Overridepublic void changeAvatar(Integer uid, String avatar, String username) {//查询当前用户数据是否存在User result = userMapper.findByUid(uid);//进行异常判断if(result==null||result.getIsDelete().equals(1)){throw new UserNotFoundException("用户数据不存在");}Integer rows = userMapper.updateAvatarByUid(uid, avatar, username, new Date());if(rows!=1){throw new UpdateException("更新用户头像产生未知的异常");}}/*** 定义一个MD5算法加密*/private String getMD5Password(String password,String salt){//进行加密(三次)for(int i=0;i<3;i++){password=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();}return password;}}

具体异常实现

控制层

1.首先先定义一个传递后端数据的类(传递JSON数据)

将状态码以及状态描述信息and数据封装到里面,方便传给前端

package puterstore.util;/*** @author diao /3/22*/import java.io.Serializable;/*** Json格式的数据进行响应* 将状态码、状态描述信息、以及数据封装到一个类中* 将这个类作为方法的返回值返回给前端浏览器*/public class JsonResult<E> implements Serializable {/*状态码*/private Integer state;/*描述信息*/private String message;/*数据(类型是不确定的)*/private E data;public JsonResult() {}public JsonResult(Integer state) {this.state = state;}//构造一个状态码+数据的对象public JsonResult(Integer stat,E data){this.state=stat;this.data=data;}//异常信息的捕获,将捕获的信息给到messagepublic JsonResult(Throwable e){this.message=e.getMessage();}public Integer getState() {return state;}public void setState(Integer state) {this.state = state;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public E getData() {return data;}public void setData(E data) {this.data = data;}}

2.控制器:

实现业务功能,并且将数据封装到JsonResult中(进行数据响应)

2.1为了简便,我们可以设置一个控制器的基类(专门处理异常的)——>根据具体情况来封装数据

package puterstore.controller;import puterstore.controller.ex.*;import puterstore.entity.Address;import puterstore.service.ex.*;import puterstore.util.JsonResult;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.ExceptionHandler;import java.nio.file.AccessDeniedException;/*** @author diao /3/23*///这也是处理前端请求的,处理前端抛出的异常,并且将方法返回值传递给前端@Controllerpublic class BaseController {/*操作成功的状态码*/public static final int OK=200;/*用于统一处理该异常,方法充当请求处理的方法,返回给到前端*/@ExceptionHandler({ServiceException.class,FileUploadException.class})public JsonResult<Void> handleException(Throwable e){JsonResult<Void> result = new JsonResult<>(e);//根据不同异常的抛出,设置不同的响应码和messageif(e instanceof UsernameDuplicatedException){result.setState(4000);result.setMessage("用户名已经被占用");}else if(e instanceof AddressCountLimitException){result.setState(4001);result.setMessage("用户收货地址超出上限的异常");}else if(e instanceof AddressNotFoundException){result.setState(4002);result.setMessage("用户的收货地址不存在");}else if(e instanceof AccessDeniedException){result.setState(4004);result.setMessage("非法访问收货地址");}else if(e instanceof ProductNotFoundException){result.setState(4005);result.setMessage("查不到商品数据");}else if(e instanceof CartNotFoundException){result.setState(4006);result.setMessage("购物车中数据不存在异常");}else if(e instanceof InsertException){result.setState(5000);result.setMessage("插入数据时产生未知的异常");// 关于登录的两个异常}else if(e instanceof PasswordNotMatchException){result.setState(5002);result.setMessage("用户名的密码错误");}else if(e instanceof UserNotFoundException){result.setState(5001);result.setMessage("用户数据不存在异常");// 更新数据得到异常}else if(e instanceof UpdateException){result.setState(5001);result.setMessage("更新数据时产生未知异常");}else if(e instanceof DeleteException){result.setState(5002);result.setMessage("删除数据时产生未知的异常");}else if(e instanceof FileEmptyException){result.setState(6000);}else if(e instanceof FileSizeException){result.setState(6001);}else if(e instanceof FileTypeException){result.setState(6002);}else if(e instanceof FileStateException){result.setState(6003);}else if(e instanceof FileUploadIOException){result.setState(6004);}return result;}}

2.2控制器:调用业务类方法返回Json数据

这里提个问:为什么注入的是接口而不是实现类?:这是多态的体现,你注入实现类也是可以的,但是万一你有点多个实现类实现这个接口,岂不是都要注入,麻烦了——>其实就是根据对象引用的实际类来执行方法,实际类就是这里的实现类(10条消息) 多态_一大三千@大千世界的博客-CSDN博客_多态

package puterstore.controller;import puterstore.controller.ex.*;import puterstore.entity.User;import puterstore.service.IUserService;import puterstore.service.ex.InsertException;import puterstore.service.ex.UsernameDuplicatedException;import puterstore.service.impl.UserServiceImpl;import puterstore.util.JsonResult;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpSession;import java.io.File;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.UUID;/*** @author diao /3/22*///这里是返回json数据(被JsonResult类型的)@RestController@RequestMapping("users")public class UserController extends BaseController{@Autowiredprivate IUserService userService;/**1、接收数据方式:请求处理方法的参数列表设置为pojo类型来接收前端数据* SpringBoot会将前端的URL地址上的参数名和pojo类的属性名进行比较,如果相同* 就会将值注入到pojo类的对应属性上* @param user* @return*/@RequestMapping("reg")public JsonResult<Void> reg(@RequestBody User user){userService.reg(user);return new JsonResult<Void>(OK);}/**2、登录功能,每次登录会将数据放入session* 接收数据形式:如果参数是非pojo类型* 那么SpringBoot会将请求的参数名和方法的参数名直接进行比较,* 如果相同则自动注入* @param username* @param password* @return*/@RequestMapping("login")public JsonResult<User> login(String username,String password,HttpSession session){//1.业务login方法,将封装的user信息放到JsonResult中;User data = userService.login(username, password);//3.向session对象中完成数据绑定(这里session是全局的)session.setAttribute("uid",data.getUid());session.setAttribute("username",data.getUsername());//4.打印获取session中的数据System.out.println(getuidFromSession(session));System.out.println(getUsernameFromSession(session));//2.将状态码数据封装到JsonResult中return new JsonResult<User>(OK,data);}/**@Session 获取session对象* 相当于是一个工具类,获取session中的uid,有利于减少代码冗余* @return*/public final Integer getuidFromSession(HttpSession session){return Integer.valueOf(session.getAttribute("uid").toString());}public final String getUsernameFromSession(HttpSession session){return session.getAttribute("username").toString();}/**** @param oldPassword* @param newPassword* @param session* @return*/@RequestMapping("change_password")public JsonResult<Void> changePassword(String oldPassword,String newPassword,HttpSession session){//uid和username我们直接从session里面获取就好了Integer uid = getuidFromSession(session);String username = getUsernameFromSession(session);//执行业务操作userService.changePassword(uid,username,oldPassword,newPassword);return new JsonResult<>(OK);}@RequestMapping("get_by_uid")public JsonResult<User> getByUid(HttpSession session){User result = userService.getByUid(getuidFromSession(session));return new JsonResult<User>(OK,result);}/*** 这个user对象由前端传递* @param user* @param session* @return*/@RequestMapping("change_info")public JsonResult<Void> changeInfo(User user, HttpSession session){//要完成修改资料需要的数据:username、phone、email、gender//uid需要再次封装到user对象中Integer uid = getuidFromSession(session);String username = getUsernameFromSession(session);userService.changeInfo(uid,username,user);return new JsonResult<>(OK);}/*设置上传文件最大值*/public static final int AVATAR_MAX_SIZE=10*1024*1024;/*限制上传文件的类型*/public static final List<String> AVATAR_TYPE=new ArrayList<>();static{//将文件类型放入集合中AVATAR_TYPE.add("image/jpeg");AVATAR_TYPE.add("image/png");AVATAR_TYPE.add("image/bmp");AVATAR_TYPE.add("image/gif");}/*** MultipartFile接口是SpringMvc提供的一个接口,这个接口包装了文件数据(任何类型的file都可以接收)* @param session:里面取出username,uid* @param file:MultipartFile类型,名字必须是file,前端页面有个name叫file的会自动寻找,* 将数据包给到控制层参数名字叫file的* @RequestParam("xxx"):与前端表单的数据进行绑定* @return*/@RequestMapping("change_avatar")public JsonResult<String> changeAvatar(HttpSession session,@RequestParam("file") MultipartFile file){//1.判断文件是否为nullif(file.isEmpty()){throw new FileEmptyException("文件为空");}if(file.getSize()>AVATAR_MAX_SIZE){throw new FileSizeException("文件超出限制,不得超过"+(AVATAR_MAX_SIZE/1024)+"KB的头像文件");}//2.判断上传的文件类型是否在AVATAR_TYPE里面String contentType = file.getContentType();System.out.println(contentType);if(!AVATAR_TYPE.contains(contentType)){throw new FileTypeException("不支持使用该类型文件作为头像,运行文件类型:\n"+AVATAR_TYPE);}//3.获取当前项目的绝对磁盘路径(就是项目路径)String parent = session.getServletContext().getRealPath("upload");System.out.println(parent);//4.dir表示保存头像文件的文件夹File dir = new File(parent);if(!dir.exists()){//如果不存在的话,就会创建一个dir.mkdirs();}//保存头像文件的文件名String originalFilename = file.getOriginalFilename();//得到文件后缀名称:先取得.的索引,然后再利用substringint beginIndex = originalFilename.lastIndexOf(".");String suffix = originalFilename.substring(beginIndex);//5.得到全新的文件名String filename = UUID.randomUUID().toString() + suffix;//6.在指定的目录下创建全新的文件,dest表示保存头像文件File dest = new File(dir, filename);//7.执行保存的头像文件,将之前的文件中的数据放到新的文件中try {file.transferTo(dest);} catch (IOException e) {throw new FileUploadIOException("上传文件时出现读写错误");} catch (FileStateException e){throw new FileStateException("文件状态异常");}//8.获取uid以及username和头像路径方便执行业务层的操作Integer uid = getuidFromSession(session);String username = getUsernameFromSession(session);//头像相对路径,作为文件夹upload需要//String avatar="/upload/"+filename;userService.changeAvatar(uid,avatar,username);//9.返回用户头像路径给到前端,用于头像展示return new JsonResult<>(OK,avatar);}/*** //需要调用业务层的接口*@Autowired*private IUserService userService;**@RequestMapping("reg")*public JsonResult<Void> reg(User user){* //1、创建响应结果集* JsonResult<Void> result = new JsonResult<>();** //2.进行业务操作,若出现异常设置响应状态码和信息* try {* userService.reg(user);* result.setState(200);* result.setMessage("用户注册成功");* } catch (UsernameDuplicatedException e) {* result.setState(4000);* result.setMessage("用户名被占用");* }catch (InsertException e){* result.setState(5000);* result.setMessage("注册时产生未知异常导致注册失败");* }** //3.返回json格式数据* return result;*}*/}

2.2控制器下的异常

控制器其实就是与前端进行对接的,拿到前端的给的数据完成传来的请求;可以理解为往下递归

前端页面

这里只举例:

大体上:当请求正常,前端将data给到指定处理请求的controller,并且将服务器响应内容给到到前端的success(响应的内容以参数的形式给到success里function方法参数上)

注册:

当页面起不来的时候,可以尝试刷新idea缓存重新启动,因为idea对js兼容性不是很好;

登录:

上传头像的前端ajax:

<script>$(document).ready(function () {//先获取cookie里面的avatar值let avatar = $.cookie("avatar");console.log(avatar)//页面一加载,就将id为img—avatar的src属性设置为avatar$("#img-avatar").attr("src",avatar);});$("#btn-change-avatar").click(function () {$.ajax({url: "/users/change_avatar",type: "POST",//将第一个表单传入FormData中进行储存,而不是servlize()了data: new FormData($("#form-change-avatar")[0]),processData: false,//处理数据的形式contentType: false,//提交数据的形式dataType: "JSON",success: function (json) {if(json.state==200){alert("头像上传成功");//将服务器端返回的头像地址设置img标签的src上$("#img-avatar").attr("src",json.data);//data当中只有一个url值$.cookie("avatar",json.data,{expires: 7});}else{alert("头像显示不出来");}}})})</script>

修改密码:

<script type="text/javascript">$("#btn-change-password").click(function (){$.ajax({url: "/users/change_password",type: "POST",data: $("#form-change-password").serialize(),dataType: "JSON",success: function (json) {if(json.state==200){alert("密码修改成功");}else{alert("密码修改失败");}},error: function (xhr) {alert("修改密码时产生未知的异常");}})})</script>

拦截器

其实拦截器也是用的aop思想,进行切面处理,prehandle方法在DispatcherServelet之前处理

1.先通过实现HandlerInterceptor自定义一个拦截器

根据session中是否有uid进行判断——>false就是拦截

package puterstore.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** @author diao /3/24*//*自定义一个拦截器*///加载当前的拦截器并且将其注册到容器中public class LoginInterceptor implements HandlerInterceptor {/*** 检测session对象中是否含有uid数据,如果没有就是未完成登录,重定向到登录页面* @param request 请求对象* @param response 响应对象* @param handler 处理器(url+controller:作映射的)* @return 返回true表示放行当前请求,否则拦截请求* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Object obj = request.getSession().getAttribute("uid");if(obj==null) {//session中无uid说明未登录,重定向到登录页面response.sendRedirect("/web/login.html");return false;}//放行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}}

2.通过实现WebMvcConfigurer接口重写addInterceptors()方法——>将自定义的拦截器进行注册

并且指定白名单,将需要放行(静态资源、登录页面、首页)放入集合;

package puterstore.config;import puterstore.interceptor.LoginInterceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.ArrayList;import java.util.List;/*** @author diao /3/25*///实现webMvcConfigurer接口,完成自定义一些功能配置@Configuration//这个需要注册到容器中需要Configuration注解public class LoginInterceptorConfigurer implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//1.创建自定义的拦截器对象HandlerInterceptor interceptor = new LoginInterceptor();//2.配置白名单,将其放入list集合中List<String> patterns = new ArrayList<>();patterns.add("/bootstrap3/**");patterns.add("/css/**");patterns.add("/images/**");patterns.add("/js/**");patterns.add("/web/register.html");patterns.add("/web/login.html");patterns.add("/web/index.html");patterns.add("/web/product.html");patterns.add("/users/reg");patterns.add("/users/login");//将省市区列表信息放入白名单中patterns.add("/districts/**");//将商品类的信息放入白名单中patterns.add("/products/**");//3.完成拦截器的注册:addPathPatterns代表拦截路径,excludePathPatterns代表白名单registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns(patterns);}}

单元测试

mapper接口测试

package puterstore.mapper;import puterstore.entity.User;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.Date;/*** @author diao /3/21*///@SpringBootTest表示这个类是一个测试类(特点:不会随同项目打包操作)@SpringBootTestpublic class UserMapperTests {//idea有自动检测功能,接口被mybatis动态代理实现放入容器了;@Autowiredprivate UserMapper userMapper;/**单元测试方法可以独立运行,提高代码运行效率* 1.必须被@Test修饰* 2.返回值必须是void* 3.方法的参数列表不指定任何类型* 4.访问修饰符必须是public*/@Testpublic void insert(){User user = new User();user.setUsername("Fairy");user.setPassword("2002514wyh11");Integer rows = userMapper.insert(user);System.out.println(rows);}@Testpublic void findByUsername(){User user = userMapper.findByUsername("Fairy");// 打印user信息System.out.println(user);}@Testpublic void updatePasswordByUid(){userMapper.updatePasswordByUid(7,"123","管理员",new Date());}@Testpublic void findByUid(){System.out.println(userMapper.findByUid(7));}@Testpublic void updateInfoByUid(){//1.将uid,phone,email,gender,modifiedUser,modifiedTime封装到user中User user = new User();user.setUid(7);user.setPhone("18175143063");user.setEmail("746879613@");user.setGender(1);user.setModifiedUser("系统管理员");user.setModifiedTime(new Date());//2.调用userMapper底层方法进行修改用户信息Integer rows = userMapper.updateInfoByUid(user);System.out.println("rows="+rows);}@Testpublic void updateAvatarByUid(){userMapper.updateAvatarByUid(8,"/upload/avatar.png","管理员",new Date());}}

业务类测试

package puterstore.service;import puterstore.entity.User;import puterstore.service.ex.ServiceException;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;/*** @author diao /3/22*/@SpringBootTestpublic class UserServiceTests {@Autowiredprivate IUserService userService;@Testpublic void reg(){try {User user = new User();user.setUsername("test026");user.setPassword("2002514wyh11");userService.reg(user);System.out.println("ok");} catch (ServiceException e) {//因为业务层可能会抛出异常//获取类的对象再获取类的名称System.out.println(e.getClass().getSimpleName());//获取异常类的信息System.out.println(e.getMessage());}}@Testpublic void login(){try {User user = userService.login("test01", "123");System.out.println(user);} catch (ServiceException e) {//获取异常信息System.out.println(e.getClass().getSimpleName());System.out.println(e.getMessage());}}@Testpublic void changePassword(){userService.changePassword(8,"test02","2002514wyh11","123");}//通过uid获取个人资料用户数据@Testpublic void getByUid(){User user = userService.getByUid(8);System.out.println(user);}@Testpublic void changeInfo(){//1.创建一个User对象,里面封装个人资料数据User user = new User();user.setPhone("18175143063");user.setEmail("746879613@");user.setGender(0);userService.changeInfo(8,"test02",user);}@Testpublic void changeAvatar(){userService.changeAvatar(8,"/upload/test.png","小明");}}

如果觉得《电脑商城项目总结-01用户管理模块(注册 登录 修改密码 个人信息 上传头像)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。