基于SpringBoot从零构建博客网站-开发上传模块和修改头像密码

上传模块在web开发中是很常见的功能也是很重要的功能,在web应用中需要上传的可以是图片、pdf、压缩包等其它类型的文件,同时对于图片可能需要回显,对于其它文件要能够支持下载等。在守望博客系统中对于上传模块进行统一管理,同时对于上传不同的类型文件,留有自定义实现机制的接口,也即可扩展。

基于上传模块机制,就可以实现修改头像功能了。同时顺带将修改密码的功能也一起实现,这个修改密码的功能相对就很简单了。

1、可扩展上传模块

统一上传模块的体现就是上传所有类型的文件,都是调用统一的一个接口,即上传接口唯一;同时对于具体上传的类型文件,如有特殊处理的可以自定义实现处理方法。

对于上传的文件能够有自定义的实现机制,则需要一个上传文件的处理接口,即:IUploadHandler,内容如下:

/**
* 上传文件处理接口类
*
* @author lzj
* @since 1.0
* @date [2019-07-09]
*/
public interface IUploadHandler {

/**
* 上传文件处理方法
* 文件上传成功,返回文件的相关信息
* 文件上传失败, 返回null
*
* @param file
* @param distType
* @param userId

* @return
* @throws Exception
*/
public Object upload(MultipartFile file, String distType, String userId) throws Exception;

/**
* 下载文件
*
* @param fileId
* @param response
* @throws Exception
*/
public void download(String fileId, HttpServletResponse response) throws Exception;

/**
* 根据条件列出文件信息
*
* @param distType
* @param userId
* @return
* @throws Exception
*/
public Object list(String distType, String userId) throws Exception;
}

目前本版本中暂定有3个方法,即:

  • upload方法,用于处理自定义上传文件方式;
  • download方法,用于处理自定义下载的方式;
  • list方法,用于处理自定义列出文件列表的方式。

这里以上传头像图片为例,则上传头像的实现类UploadAvatarHandler,内容如下:

/**
* 上传头像处理类

*
* @author lzj
* @since 1.0
* @date [2019-07-09]
*/
@Slf4j
@Component("_avatar")
public class UploadAvatarHandler implements IUploadHandler {

@Autowired
private IUserService userService;

@Resource(name = "configCache")
private ICache<config> configCache;

@Override
public Object upload(MultipartFile file, String distType, String userId) throws Exception {
Map<string> result = new HashMap<string>();
try {
// 获取图片的大小
long fileSize = file.getSize();

// 图片大小不能超过2M, 2M = 2 * 1024 * 1024B = 2097152B
if (fileSize > 2097152L) {
throw new TipException("您上传的图片超过2M");
}

Config config = configCache.get(Config.CONFIG_IMG_AVATAR_PATH);
// 保存头像的根目录
String basePath = config.getConfigValue();
if (!basePath.endsWith("/")) {
basePath += "/";
}

// 根据当前时间构建yyyyMM的文件夹,建立到月的文件夹
String dateDirName = DateUtil.date2Str(new Date(), DateUtil.YEAR_MONTH_FORMAT);
basePath += dateDirName;

File imageDir = new File(basePath);
if (!imageDir.exists()) {
imageDir.mkdirs();
}

String fileNewName = IdGenarator.guid() + ".jpg";
FileUtil.copy(file.getInputStream(), new FileOutputStream(new File(imageDir, fileNewName)));


// 获取用户信息
User user = userService.getById(userId);
user.setPicture(dateDirName + "/" + fileNewName);

// 更新信息
userService.updateById(user);

result.put("success", true);
result.put("msg", "上传头像成功");
} catch (TipException e) {
result.put("success", false);
result.put("msg", e.getMessage());
} catch (Exception e) {
log.error("上传头像失败", e);
result.put("success", false);
result.put("msg", "上传头像失败");
}

return result;
}

@Override
public void download(String fileId, HttpServletResponse response) throws Exception {
}

@Override
public Object list(String distType, String userId) throws Exception {
return null;
}
/<string>/<string>/<config>

这里有2个注意点,即这个@Component("_avatar"),这个类的名称最好自定义命名,最好以处理这种文件的类型为名,例如此处的是处理头像的,所以就是avatar,但是为了防止重名,所以前缀加上了下划线。

另外一个需要注意的就是,并不是所有的方法都需要实现,例如此处就没有实现download和list方法,因为头像图片不是通过流的方式回显的,而是直接通过映射到具体的图片,同时也是不需要列出头像的功能。

前面说过所有上传文件,都是调用统一的一个接口,也即是UploadController,内容如下:

/**
* 处理文件上传下载控制器类
*
* @author lzj
* @date [2019-07-09]
* @since 1.0
*/
@Slf4j
@Controller
public class UploadController {

@Autowired
private ApplicationContext context;

// 用于存储处理上传文件对象
private Map<string> uploadHandlers;

/**
* 初始化操作
*
* @throws Exception
*/
@PostConstruct
public void init() throws Exception {
uploadHandlers = context.getBeansOfType(IUploadHandler.class);
}

/**
* 上传文件
*
* @param file
* @param request
* @param session
* @return
*/
@RequestMapping(value = "/upload", method = RequestMethod.POST)
@ResponseBody
public Object upload(@RequestParam(value = "_uploadFile", required = false) MultipartFile file, HttpServletRequest request, HttpSession session) {
Object result = null;
try {
// 接收参数

// 获取上传文件类型,参数名为_fileType
String _distType = request.getParameter("_distType");

// 获取用户信息
User user = (User) session.getAttribute(Const.SESSION_USER);

result = uploadHandlers.get(_distType).upload(file, _distType, user.getUserId());
} catch (Exception e) {
log.error("上传文件失败", e);
}
return result;
}
}
/<string>

这里需要注意init方法,该方法会将IUploadHandler接口的实现类都扫描出来,同时以类名为key,实例为value返回。

同时调用上传方法时是需要带_distType参数的,该参数值要与具体IUploadHandler的实现类的类名一样,例如:上传头像就需要将 _distType = _avatar参数带过来。这样UploadController就知道具体用哪个实现类来处理。

2、修改头像

有了前面的上传模块,对于修改头像就简单多了,首先需要实现上传头像的实现类,即UploadAvatarHandler类,代码在上方已经罗列了此处省略。

加载出修改头像页面的核心的如下:

/**
* 加载出修改头像页面

*
* @return
*/
@RequestMapping(value = "/user/avatar", method = RequestMethod.GET)
public String avatar(HttpSession session, Model model) {
// session中的信息
User sessionUser = (User) session.getAttribute(Const.SESSION_USER);

// 从数据库中获取用户信息
User user = userService.getById(sessionUser.getUserId());

model.addAttribute("user", user);
return Const.BASE_INDEX_PAGE + "auth/user/avatar";
}

修改头像,运用了fullAvatarEditor插件,所以核心的前台代码如下:

注意:

里面一个upload_url参数就是写上传接口的,上述中为:

upload_url: '${rc.contextPath}/upload?_distType=_avatar'

正如在前面讨论的一样的,需要带上 _distType参数

页面效果如下:

基于SpringBoot从零构建博客网站-开发上传模块和修改头像密码

注意在回显图片时,需要加上如下配置:

/**
* 静态资源配置
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 映射头像图片
String avatarPath = configCache.get(Config.CONFIG_IMG_AVATAR_PATH).getConfigValue();
if (!avatarPath.endsWith("/")) {
avatarPath += "/";
}
registry.addResourceHandler("/img/avatar/**").addResourceLocations("file:" + avatarPath);
}

3、修改密码

修改密码功能相对简单,页面效果如下:

基于SpringBoot从零构建博客网站-开发上传模块和修改头像密码

此处就只列出修改密码的核心逻辑,即:

/**
* 修改密码
*
* @param request
* @param session
* @param model
* @return
*/
@RequestMapping(value = "/user/password", method = RequestMethod.POST)
@ResponseBody
public Result password(HttpServletRequest request, HttpSession session) {
Result result = new Result();
try {
// 获取登录信息
User tempUser = (User) session.getAttribute(Const.SESSION_USER);
String userId = tempUser.getUserId();

// 接收参数
String password = request.getParameter("password");
String newPwd = request.getParameter("newPwd");
String confirmNewPwd = request.getParameter("confirmNewPwd");

if (StringUtils.isEmpty(password) || StringUtils.isEmpty(newPwd) || StringUtils.isEmpty(confirmNewPwd)) {
throw new TipException("缺少必要请求参数");
}

if (!newPwd.equals(confirmNewPwd)) {
throw new TipException("两次输入的新密码不相等");
}

// 获取用户信息
User user = userService.getById(userId);
if (!user.getPassword().equals(StringUtil.md5(password))) {
throw new TipException("旧密码输入不正确");
}

// 修改密码
user.setPassword(StringUtil.md5(newPwd));
boolean flag = userService.updateById(user);

if (!flag) {
throw new TipException("修改密码失败");
}

result.setCode(Result.CODE_SUCCESS);
result.setMsg("修改成功");
} catch (TipException e) {
result.setCode(Result.CODE_EXCEPTION);
result.setMsg(e.getMessage());
} catch (Exception e) {
log.error("修改密码失败", e);
result.setCode(Result.CODE_EXCEPTION);
result.setMsg("修改密码失败");
}
return result;
}


分享到:


相關文章: