1.总结:昨天主要是编写了根据uid和username以及avatar上传图像,但是还是没有实现上传图像的功能,今天再琢磨一下,代码好像无误,但是功能却没有达到效果
主要是在mapper中定义了根据uid,avatar,修改者,以及修改时间等参数的changeAvatarByUid()方法;再就是在xml文件中实现该方法的SQL语句。
因为在上传文件的时候容易出现文件方面的错误,所以创建了文件异常的基类FileUploadException继承RuntimeException,以及他的五个子类FileEmptyException,
FileSizeException,FileTypeException,FileStateException,FileUploadIOException等子类并继承他的方法。
在service接口中定义uid和username以及avatar的抽象方法,在它的实现类中,首先根据finByUid()方法查询用户数据,并判断用户是否存在,是否逻辑删除;再调用updateAvatarByUid()方 法进行图像的修改。
在controller中,首先我们需要定义静态的文件最大规格以及上传类型以及允许的类型;再判断文件件是否为空,是否尺寸是否超过限制,文件类型是否符合;获取当前运行项目路径,并创 建文件夹,再获取上传文件的文件名,并根据获取的后缀进行重新命名,最后根据运行项目路径以及重新命名的文件名创建一个文件并保存来完成文件的上传;
从session中获取uid和username,再根据传入的图像进行图像修改
mapper
package com.ku.store.mapper;
import com.ku.store.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
public interface UserMapper {
Integer insert(User user);
User findByUsername(String username);
//@Param作用:给参数命名,命名后根据名字得到参数值,正确地将参数传入SQL
Integer updatePasswordByUid(@Param("uid") Integer uid,
@Param("password") String password,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime")Date modifiedTime);
User findByUid(Integer uid);
Integer updateInfoByUid(User user);
Integer updateAvatarByUid(@Param("uid") Integer uid,
@Param("avatar") String avatar,
@Param("modifiedUser") String modifiedUser,
@Param("modifiedTime") Date modifiedTime);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ku.store.mapper.UserMapper">
<resultMap id="UserEntityMap" type="com.ku.store.entity.User">
<id column="uid" property="uid"/>
<result column="is_delete" property="isDelete"/>
<result column="created_user" property="createdUser"/>
<result column="created_time" property="createdTime"/>
<result column="modified_user" property="modifiedUser"/>
<result column="modified_time" property="modifiedTime"/>
</resultMap>
<!--useGeneratedKeys="true" :如果插入的表id以自增列为主键,则允许 JDBC 支持自动生成主键,
并可将自动生成的主键id返回。
keyProperty="uid"
useGeneratedKeys="true"配合keyProperty="uid":将一个对象保存成功后,将插入的这条主键id返回,
并保存到对象中,供后续使用
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="uid">
INSERT into
store.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 id="findByUsername" resultMap="UserEntityMap">
select * from store.t_user where username = #{username}
</select>
<update id="updatePasswordByUid">
update
store.t_user
set
password = #{password},
modified_user = #{modifiedUser},
modified_time = #{modifiedTime}
where
uid = #{uid}
</update>
<!--uid = #{uid}q前面是是字段值,后面是属性值-->
<select id="findByUid" resultMap="UserEntityMap">
select
*
from
store.t_user
where
uid = #{uid}
</select>
<update id="updateInfoByUid">
update
store.t_user
set
<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}
where
uid = #{uid}
</update>
<update id="updateAvatarByUid">
update
store.t_user
set
avatar = #{avatar},
modified_user = #{modifiedUser},
modified_time = #{modifiedTime}
where
uid = #{uid}
</update>
</mapper>
service
package com.ku.store.service;
import com.ku.store.entity.User;
public interface IUserService {
/**
* 通过用户进行注册操作
* @param user
*/
void reg(User user);
/**
* 通过用户名和密码进行登录操作
* @param username 用户名
* @param password 密码
* @return 登录成功的用户数据
*/
/**
*登录成功后需要获取用户的id识别用户身份,
* 还需要获取用户的用户名,头像等户数显示在软件界面上
*/
User login(String username, String password);
/**
* 通过旧密码和新密码以及用户id和用户名修改用户密码
* @param uid
* @param username
* @param oldPassword
* @param newPassword
*/
void changePassword(Integer uid, String username,
String oldPassword, String newPassword);
/**
* 根据uid获取当前登录用户信息
* @param uid
* @return
*/
User getByUid(Integer uid);
/**
* 根据当前登录用户的uid和username修改用户资料
* @param uid
* @param username
* @param user
*/
void changeInfo(Integer uid, String username, User user);
/**
* 根据当前登录用户的uid和username修改用户图像
* @param uid 当前登录用户id
* @param username 当前登录用户名
* @param avatar 用户新图像路径
*/
void changeAvatar(Integer uid, String username, String avatar);
}
serviceImpl
package com.ku.store.service.impl;
import com.ku.store.entity.User;
import com.ku.store.mapper.UserMapper;
import com.ku.store.service.IUserService;
import com.ku.store.service.exception.*;
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;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public void reg(User user) {
//1.1 根据user参数获取注册的用户名
//1.2 调用UserMapper的findByUsername根据用户名查询用户信息
//1.3 判断查询结果是否为空,若为空,表示用户名已占用,抛出UsernameDuplicateException
String username = user.getUsername();
User result = userMapper.findByUsername(username);
if(result != null){
throw new UsernameDuplicateException("注册的用户"+username+"已被占用!");
}
//2.1创建当前时间对象:
// 2.2 补全数据:加密后的密码
// 2.3 补全数据:盐值
// 2.4 补全数据:IsDelete(0)
// 2.5 补全数据:4项日志属性
Date now = new Date();
String salt = UUID.randomUUID().toString().toUpperCase();
String md5Password = getMd5Password(user.getPassword(), salt);
user.setPassword(md5Password);
user.setSalt(salt);
user.setIsDelete(0);
user.setCreatedUser(username);
user.setCreatedTime(now);
user.setModifiedUser(username);
user.setModifiedTime(now);
//3.1用户名没有被注册,则允许注册
//3.2调用UserMapper的insert方法,执行注册并返回结果,判断是否不为1,
// 是则插入错误抛出InsertException异常
Integer rows = userMapper.insert(user);
if(rows != 1){
throw new InsertException("注册用户出现未知问题,请联系系统管理员!");
}
}
private String getMd5Password(String password, String salt){
/**
* 加密规则:
* 1.无视原始密码强度
* 2.使用UUID作为盐值,在原始密码两侧拼接
* 3.循环加密3次
*/
for (int i = 0; i <3 ; i++) {
password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes()).toUpperCase();
}
return password;
}
@Override
public User login(String username, String password) {
//调用userMapper的findByUsername()方法,根据username查询用户信息
User result = userMapper.findByUsername(username);
//判断查询结果是否为空,是:抛出UserNotFoundException
//判断查询结果中的isDelete是否为1,是:抛出UserNotFoundException异常
if (result == null ){
throw new UserNotFoundException("用户没找到!");
}
if(result.getIsDelete() == 1){
throw new UserNotFoundException("用户没找到!");
}
//从查询结果中获取盐值
//调用getMd5Password()方法,将password饿salt结合起来加密
String MD5PassWord = getMd5Password(password, result.getSalt());
if (!MD5PassWord.equals(result.getPassword())){
throw new PasswordNotMatchException("用户名密码错误!");
}
//创建新的User对象,将查询的uid,username,avatar封装到新的user对象中,返回新的对象
//注意:为什么不直接返回整个查询到的用户信息呢,实现数据的有效性(只取所需)
User user = new User();
user.setUid(result.getUid());
user.setUsername(result.getUsername());
user.setAvatar(result.getAvatar());
return user;
}
@Override
public void changePassword(Integer uid, String username, String oldPassword, String newPassword) {
//调用UserMapper的findByUid()方法,根据uid查询用户数据
User result = userMapper.findByUid(uid);
if (result == null){
throw new UserNotFoundException("用户不存在!");
}
if(result.getIsDelete() == 1){
throw new UserNotFoundException("用户不存在!");
}
//从查询结果中取出盐值
//将参数oldPassword结合盐值加密,得到oldMd5Password
//判断查询结果中的password()与oldMd5Password是否不一致
//不一致就抛出PasswordNotMatchException异常
String oldMd5Password = getMd5Password(oldPassword, result.getSalt());
if (!result.getPassword().equals(oldMd5Password)){
throw new PasswordNotMatchException("密码不匹配!");
}
String newMd5Password = getMd5Password(newPassword, result.getSalt());
Date now = new Date();
Integer rows = userMapper.updatePasswordByUid(uid, newMd5Password, username, now);
if (rows != 1){
throw new UpdateException("更新用户数据异常!");
}
}
@Override
public User getByUid(Integer uid) {
//调用UserMapper的findByUid()方法,根据uid查询用户数据
User result = userMapper.findByUid(uid);
if (result == null){
throw new UserNotFoundException("用户不存在!");
}
if(result.getIsDelete() == 1){
throw new UserNotFoundException("用户不存在!");
}
User user = new User();
user.setUid(uid);
user.setUsername(result.getUsername());
user.setPhone(result.getPhone());
user.setEmail(result.getEmail());
user.setGender(result.getGender());
return user;
}
@Override
public void changeInfo(Integer uid, String username, User user) {
User result = userMapper.findByUid(uid);
if (result == null){
throw new UserNotFoundException("用户不存在!");
}
if(result.getIsDelete() == 1){
throw new UserNotFoundException("用户不存在!");
}
user.setUid(uid);
user.setModifiedUser(username);
user.setModifiedTime(new Date());
Integer rows = userMapper.updateInfoByUid(user);
if (rows !=1){
throw new UpdateException("修改异常!");
}
}
@Override
public void changeAvatar(Integer uid, String username, String avatar) {
User result = userMapper.findByUid(uid);
if (result == null){
throw new UserNotFoundException("用户不存在!");
}
if(result.getIsDelete() == 1){
throw new UserNotFoundException("用户不存在!");
}
Integer rows = userMapper.updateAvatarByUid(uid, avatar, username, new Date());
if (rows != 1){
throw new UpdateException("修改异常!");
}
}
}
BaseController
package com.ku.store.controller;
import com.ku.store.service.exception.*;
import com.ku.store.utils.JsonResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpSession;
/**
* 该类用于响应成功的状态码以及统一处理异常 ,简化原来的controller
*/
//控制类基类
public class BaseController {
public static final int OK = 200;
//统一处理方法抛出的异常,此注解表示专门处理这个类的异常
//注意:不要使用相同的注解参数,例如:Throwable e
@ExceptionHandler({ServiceException.class, FileUploadException.class})
public JsonResult<Void>handleException(Throwable e){
JsonResult<Void> result = new JsonResult<>();
if (e instanceof UsernameDuplicateException){
result.setState(400);
result.setMessage("用户名已存在!");
}else if(e instanceof UserNotFoundException){
result.setState(401);
result.setMessage("用户名未找到!");
}else if(e instanceof PasswordNotMatchException){
result.setState(402);
result.setMessage("密码不匹配!");
}else if(e instanceof InsertException){
result.setState(500);
result.setMessage("插入用户数据出现未知错误!");
}else if(e instanceof UpdateException){
result.setState(501);
result.setMessage("更改用户数据出现未知错误!");
}else if(e instanceof FileEmptyException){
result.setState(600);
result.setMessage("文件不能为空!");
}else if(e instanceof FileSizeException){
result.setState(601);
result.setMessage("文件超过限制!");
}else if(e instanceof FileTypeException){
result.setState(602);
result.setMessage("文件类型不允许!");
}else if(e instanceof FileStateException){
result.setState(603);
result.setMessage("文件状态不正常!");
}else if(e instanceof FileUploadIOException){
result.setState(604);
result.setMessage("文件上传流错误!");
}
return result;
}
/**
* 从HttpSession对象中获取uid
* @param session HttpSession对象
* @return 当前登录用户id
*/
protected final Integer getUidFromSession(HttpSession session){
return Integer.valueOf(session.getAttribute("uid").toString());
}
/**
* 从HttpSession对象中获取username
* @param session HttpSession对象
* @return 当前登录用户的username
*/
protected final String getUsernameFromSession(HttpSession session){
return session.getAttribute("username").toString();
}
}
UserController
package com.ku.store.controller;
import com.ku.store.entity.User;
import com.ku.store.service.exception.*;
import com.ku.store.service.impl.UserServiceImpl;
import com.ku.store.utils.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
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;
/**
* 处理用户相关请求的控制类
*/
@RestController
@RequestMapping("/users")
public class UserController extends BaseController {
@Autowired
private UserServiceImpl userService;
@RequestMapping("/reg")
public JsonResult<Void>reg(User user){
userService.reg(user);
return new JsonResult<>(OK);
}
@RequestMapping("/login")
public JsonResult<User> login(String username, String password, HttpSession session){
//调用业务对象方法执行登录,并获取返回值
User user = userService.login(username, password);
//登录成功后,将uid和username存入到HttpSession中
session.setAttribute("uid", user.getUid());
session.setAttribute("username", user.getUsername());
//将以上返回值和状态码OK封装到相应结果中并返回
return new JsonResult<User>(OK, user);
}
@RequestMapping("/change_password")
//在这里报错为空是因为并还没有登录,所以导致的
//lower密码还是888888
public JsonResult<Void> changePassword(String oldPassword, String newPassword,
HttpSession session){
//调用session.getAttribute("")获取uid和username
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
//调用业务对象执行修改密码
userService.changePassword(uid, username, oldPassword, newPassword);
return new JsonResult<Void>(OK);
}
@RequestMapping("/get_by_uid")
public JsonResult<User> getByUid(HttpSession session){
//调用session.getAttribute("")获取uid和username
Integer uid = getUidFromSession(session);
User user = userService.getByUid(uid);
//调用业务对象执行修改密码
return new JsonResult<User>(OK, user);
}
@RequestMapping("/change_info")
public JsonResult<User> changeInfo(User user, HttpSession session){
//调用session.getAttribute("")获取uid和username
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
userService.changeInfo(uid, username, user);
return new JsonResult<User>(OK, user);
}
/** 头像文件大小的上限值(10MB) */
public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
/** 允许上传的头像的文件类型 */
public static final List<String> AVATAR_TYPES = new ArrayList<String>();
/** 初始化允许上传的头像的文件类型 */
static {
AVATAR_TYPES.add("image/jpg");
AVATAR_TYPES.add("image/png");
AVATAR_TYPES.add("image/bmp");
AVATAR_TYPES.add("image/gif");
}
@PostMapping("change_avatar")
//先处理异常:首先判断文件是否为空,然后判断文件大小是否超出限制,再判断文件类型是否超出限制
//后创建文件:先获取当前项目绝对路径,然后保存图像文件夹,再保存头像文件名,之后创建文件对象
//最后实现:先获取图像路径,然后从session中获取用户id和用户名,再执行changeAvatar()方法完成头像修改,
// 最后返回前端响应
public JsonResult<String> changeAvatar(@RequestParam("file") MultipartFile file, HttpSession session) {
// 判断上传的文件是否为空
if (file.isEmpty()) {
// 是:抛出异常
throw new FileEmptyException("上传的头像文件不允许为空");
}
// 判断上传的文件大小是否超出限制值
if (file.getSize() > AVATAR_MAX_SIZE) { // getSize():返回文件的大小,以字节为单位
// 是:抛出异常
throw new FileSizeException("不允许上传超过" + (AVATAR_MAX_SIZE / 1024) + "KB的头像文件");
}
// 判断上传的文件类型是否超出限制
String contentType = file.getContentType();
// boolean contains(Object o):当前列表若包含某元素,返回结果为true;若不包含该元素,返回结果为false
if (!AVATAR_TYPES.contains(contentType)) {
// 是:抛出异常
throw new FileTypeException("不支持使用该类型的文件作为头像,允许的文件类型:" + AVATAR_TYPES);
}
// 获取当前项目的绝对磁盘路径,获取上传到服务器上的文件路径
String parent = session.getServletContext().getRealPath("upload");
System.out.println(parent);
// 保存头像文件的文件夹
File dir = new File(parent);
if (!dir.exists()) {
dir.mkdirs();
}
// 保存的头像文件的文件名
String suffix = "";
String originalFilename = file.getOriginalFilename();
int beginIndex = originalFilename.lastIndexOf(".");
if (beginIndex > 0) {
suffix = originalFilename.substring(beginIndex);
}
String filename = UUID.randomUUID().toString() + suffix;
// 创建文件对象,表示保存的头像文件
File dest = new File(dir, filename);
// 执行保存头像文件
try {
file.transferTo(dest);
} catch (IllegalStateException e) {
// 抛出异常
throw new FileStateException("文件状态异常,可能文件已被移动或删除");
} catch (IOException e) {
// 抛出异常
throw new FileUploadIOException("上传文件时读写错误,请稍后重新尝试");
}
// 头像路径
String avatar = "/upload/" + filename;
// 从Session中获取uid和username
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
// 将头像写入到数据库中
userService.changeAvatar(uid, username, avatar);
// 返回成功头像路径
return new JsonResult<String>(OK, avatar);
}
}
2.反思:现在觉得自己没有多做的就是这个文件的上传,但是自己代码跟别人写的一样,还是无法实现,文件的上传,不知道是前端的问题还是其他的什么问题,找找原因将其解决
3.巩固一下以前所学