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

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

1、可扩展上传模块

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

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

  1. /**
  2. * 上传文件处理接口类
  3. *
  4. * @author lzj
  5. * @since 1.0
  6. * @date [2019-07-09]
  7. */
  8. public interface IUploadHandler {
  9. /**
  10. * 上传文件处理方法
  11. * 文件上传成功,返回文件的相关信息
  12. * 文件上传失败, 返回null
  13. *
  14. * @param file
  15. * @param distType
  16. * @param userId
  17. * @return
  18. * @throws Exception
  19. */
  20. public Object upload(MultipartFile file, String distType, String userId) throws Exception;
  21. /**
  22. * 下载文件
  23. *
  24. * @param fileId
  25. * @param response
  26. * @throws Exception
  27. */
  28. public void download(String fileId, HttpServletResponse response) throws Exception;
  29. /**
  30. * 根据条件列出文件信息
  31. *
  32. * @param distType
  33. * @param userId
  34. * @return
  35. * @throws Exception
  36. */
  37. public Object list(String distType, String userId) throws Exception;
  38. }

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

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

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

  1. /**
  2. * 上传头像处理类
  3. *
  4. * @author lzj
  5. * @since 1.0
  6. * @date [2019-07-09]
  7. */
  8. @Slf4j
  9. @Component("_avatar")
  10. public class UploadAvatarHandler implements IUploadHandler {
  11. @Autowired
  12. private IUserService userService;
  13. @Resource(name = "configCache")
  14. private ICache<Config> configCache;
  15. @Override
  16. public Object upload(MultipartFile file, String distType, String userId) throws Exception {
  17. Map<String, Object> result = new HashMap<String, Object>();
  18. try {
  19. // 获取图片的大小
  20. long fileSize = file.getSize();
  21. // 图片大小不能超过2M, 2M = 2 * 1024 * 1024B = 2097152B
  22. if (fileSize > 2097152L) {
  23. throw new TipException("您上传的图片超过2M");
  24. }
  25. Config config = configCache.get(Config.CONFIG_IMG_AVATAR_PATH);
  26. // 保存头像的根目录
  27. String basePath = config.getConfigValue();
  28. if (!basePath.endsWith("/")) {
  29. basePath += "/";
  30. }
  31. // 根据当前时间构建yyyyMM的文件夹,建立到月的文件夹
  32. String dateDirName = DateUtil.date2Str(new Date(), DateUtil.YEAR_MONTH_FORMAT);
  33. basePath += dateDirName;
  34. File imageDir = new File(basePath);
  35. if (!imageDir.exists()) {
  36. imageDir.mkdirs();
  37. }
  38. String fileNewName = IdGenarator.guid() + ".jpg";
  39. FileUtil.copy(file.getInputStream(), new FileOutputStream(new File(imageDir, fileNewName)));
  40. // 获取用户信息
  41. User user = userService.getById(userId);
  42. user.setPicture(dateDirName + "/" + fileNewName);
  43. // 更新信息
  44. userService.updateById(user);
  45. result.put("success", true);
  46. result.put("msg", "上传头像成功");
  47. } catch (TipException e) {
  48. result.put("success", false);
  49. result.put("msg", e.getMessage());
  50. } catch (Exception e) {
  51. log.error("上传头像失败", e);
  52. result.put("success", false);
  53. result.put("msg", "上传头像失败");
  54. }
  55. return result;
  56. }
  57. @Override
  58. public void download(String fileId, HttpServletResponse response) throws Exception {
  59. }
  60. @Override
  61. public Object list(String distType, String userId) throws Exception {
  62. return null;
  63. }

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

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

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

  1. /**
  2. * 处理文件上传下载控制器类
  3. *
  4. * @author lzj
  5. * @date [2019-07-09]
  6. * @since 1.0
  7. */
  8. @Slf4j
  9. @Controller
  10. public class UploadController {
  11. @Autowired
  12. private ApplicationContext context;
  13. // 用于存储处理上传文件对象
  14. private Map<String, IUploadHandler> uploadHandlers;
  15. /**
  16. * 初始化操作
  17. *
  18. * @throws Exception
  19. */
  20. @PostConstruct
  21. public void init() throws Exception {
  22. uploadHandlers = context.getBeansOfType(IUploadHandler.class);
  23. }
  24. /**
  25. * 上传文件
  26. *
  27. * @param file
  28. * @param request
  29. * @param session
  30. * @return
  31. */
  32. @RequestMapping(value = "/upload", method = RequestMethod.POST)
  33. @ResponseBody
  34. public Object upload(@RequestParam(value = "_uploadFile", required = false) MultipartFile file, HttpServletRequest request, HttpSession session) {
  35. Object result = null;
  36. try {
  37. // 接收参数
  38. // 获取上传文件类型,参数名为_fileType
  39. String _distType = request.getParameter("_distType");
  40. // 获取用户信息
  41. User user = (User) session.getAttribute(Const.SESSION_USER);
  42. result = uploadHandlers.get(_distType).upload(file, _distType, user.getUserId());
  43. } catch (Exception e) {
  44. log.error("上传文件失败", e);
  45. }
  46. return result;
  47. }
  48. }

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

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

2、修改头像

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

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

  1. /**
  2. * 加载出修改头像页面
  3. *
  4. * @return
  5. */
  6. @RequestMapping(value = "/user/avatar", method = RequestMethod.GET)
  7. public String avatar(HttpSession session, Model model) {
  8. // session中的信息
  9. User sessionUser = (User) session.getAttribute(Const.SESSION_USER);
  10. // 从数据库中获取用户信息
  11. User user = userService.getById(sessionUser.getUserId());
  12. model.addAttribute("user", user);
  13. return Const.BASE_INDEX_PAGE + "auth/user/avatar";
  14. }

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

  1. <script type="text/javascript">
  2. swfobject.addDomLoadEvent(function () {
  3. var swf = new fullAvatarEditor("${rc.contextPath}/static/plugins/fullAvatarEditor/fullAvatarEditor.swf", "${rc.contextPath}/resources/plugins/fullAvatarEditor/expressInstall.swf", "swfContainer", {
  4. id: 'swf',
  5. upload_url: '${rc.contextPath}/upload?_distType=_avatar', //上传接口
  6. method: 'post', //传递到上传接口中的查询参数的提交方式。更改该值时,请注意更改上传接口中的查询参数的接收方式
  7. src_upload: 0, //是否上传原图片的选项,有以下值:0-不上传;1-上传;2-显示复选框由用户选择
  8. avatar_box_border_width: 0,
  9. avatar_sizes: '150*150',
  10. avatar_sizes_desc: '150*150像素',
  11. avatar_field_names: '_uploadFile'
  12. }, function (msg) {
  13. console.log(msg);
  14. switch (msg.code) {
  15. case 1 :
  16. break;
  17. case 2 :
  18. document.getElementById("upload").style.display = "inline";
  19. break;
  20. case 3 :
  21. if (msg.type == 0) {
  22. }
  23. else if (msg.type == 1) {
  24. alert("摄像头已准备就绪但用户未允许使用!");
  25. }
  26. else {
  27. alert("摄像头被占用!");
  28. }
  29. break;
  30. case 5 :
  31. setTimeout(function () {
  32. window.location.href = window.location.href;
  33. }, 1000);
  34. break;
  35. }
  36. }
  37. );
  38. document.getElementById("upload").onclick = function () {
  39. swf.call("upload");
  40. };
  41. });
  42. </script>

注意:

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

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

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

页面效果如下:

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

  1. /**
  2. * 静态资源配置
  3. *
  4. * @param registry
  5. */
  6. @Override
  7. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  8. // 映射头像图片
  9. String avatarPath = configCache.get(Config.CONFIG_IMG_AVATAR_PATH).getConfigValue();
  10. if (!avatarPath.endsWith("/")) {
  11. avatarPath += "/";
  12. }
  13. registry.addResourceHandler("/img/avatar/**").addResourceLocations("file:" + avatarPath);
  14. }

3、修改密码

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

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

  1. /**
  2. * 修改密码
  3. *
  4. * @param request
  5. * @param session
  6. * @param model
  7. * @return
  8. */
  9. @RequestMapping(value = "/user/password", method = RequestMethod.POST)
  10. @ResponseBody
  11. public Result password(HttpServletRequest request, HttpSession session) {
  12. Result result = new Result();
  13. try {
  14. // 获取登录信息
  15. User tempUser = (User) session.getAttribute(Const.SESSION_USER);
  16. String userId = tempUser.getUserId();
  17. // 接收参数
  18. String password = request.getParameter("password");
  19. String newPwd = request.getParameter("newPwd");
  20. String confirmNewPwd = request.getParameter("confirmNewPwd");
  21. if (StringUtils.isEmpty(password) || StringUtils.isEmpty(newPwd) || StringUtils.isEmpty(confirmNewPwd)) {
  22. throw new TipException("缺少必要请求参数");
  23. }
  24. if (!newPwd.equals(confirmNewPwd)) {
  25. throw new TipException("两次输入的新密码不相等");
  26. }
  27. // 获取用户信息
  28. User user = userService.getById(userId);
  29. if (!user.getPassword().equals(StringUtil.md5(password))) {
  30. throw new TipException("旧密码输入不正确");
  31. }
  32. // 修改密码
  33. user.setPassword(StringUtil.md5(newPwd));
  34. boolean flag = userService.updateById(user);
  35. if (!flag) {
  36. throw new TipException("修改密码失败");
  37. }
  38. result.setCode(Result.CODE_SUCCESS);
  39. result.setMsg("修改成功");
  40. } catch (TipException e) {
  41. result.setCode(Result.CODE_EXCEPTION);
  42. result.setMsg(e.getMessage());
  43. } catch (Exception e) {
  44. log.error("修改密码失败", e);
  45. result.setCode(Result.CODE_EXCEPTION);
  46. result.setMsg("修改密码失败");
  47. }
  48. return result;
  49. }

关注我

以你最方便的方式关注我:

微信公众号:

基于SpringBoot从零构建博客网站 - 设计可扩展上传模块和开发修改头像密码功能的更多相关文章

  1. 基于SpringBoot从零构建博客网站 - 技术选型和整合开发环境

    技术选型和整合开发环境 1.技术选型 博客网站是基于SpringBoot整合其它模块而开发的,那么每个模块选择的技术如下: SpringBoot版本选择目前较新的2.1.1.RELEASE版本 持久化 ...

  2. 基于SpringBoot从零构建博客网站 - 确定需求和表结构

    要确定一个系统的需求,首先需要明确该系统的用户有哪些,然后针对每一类用户,确定其需求.对于博客网站来说,用户有3大类,分别是: 作者,也即是注册用户 游客,也即非注册用户 管理员,网站维护人员 那么从 ...

  3. 基于SpringBoot从零构建博客网站 - 集成editor.md开发发布文章功能

    发布文章功能里面最重要的就是需要集成富文本编辑器,目前富文本编辑器有很多,例如ueditor,CKEditor.editor.md等.这里守望博客里面是集成的editor.md,因为editor.md ...

  4. 基于SpringBoot从零构建博客网站 - 新增创建、修改、删除专栏功能

    守望博客是支持创建专栏的功能,即可以将一系列相关的文章归档到专栏中,方便用户管理和查阅文章.这里主要讲解专栏的创建.修改和删除功能,至于专栏还涉及其它的功能,例如关注专栏等后续会穿插着介绍. 1.创建 ...

  5. 基于SpringBoot从零构建博客网站 - 开发设置主页标识和修改个人信息功能

    由于守望博客系统中支持由用户自己设置个人主页的URL的后半段,所以必须要用户设置该标识的功能,而且是用户注册登录之后自动弹出的页面,如果用户没有设置该标识,其它的操作是不能够操作的,同时要求主页标识只 ...

  6. 基于SpringBoot从零构建博客网站 - 开发文章详情页面

    文章详情页面是博客系统中最为重要的页面,登录用户与游客都可以浏览文章详情页面,只不过只有登录用户才能进行其它的一些操作,比如评论.点赞和收藏等等. 本次的开发任务只是将文章详情页面展示出来,至于一些收 ...

  7. 基于SpringBoot从零构建博客网站 - 整合ehcache和开发注册登录功能

    对于程序中一些字典信息.配置信息应该在程序启动时加载到缓存中,用时先到缓存中取,如果没有命中,再到数据库中获取同时放到缓存中,这样做可以减轻数据库层的压力.目前暂时先整合ehcache缓存,同时预留了 ...

  8. 基于SpringBoot从零构建博客网站 - 整合lombok和mybatis-plus提高开发效率

    在上一章节中<技术选型和整合开发环境>,确定了开发的技术,但是如果直接这样用的话,可能开发效率会不高,为了提高开发的效率,这里再整合lombok和mybatis-plus两个组件. 1.l ...

  9. 基于SpringBoot从零构建博客网站 - 分页显示文章列表功能

    显示文章列表一般都是采用分页显示,比如每页10篇文章显示.这样就不用每次就将所有的文章查询出来,而且当文章数量特别多的时候,如果一次性查询出来很容易出现OOM异常. 后台的分页插件采用的是mybati ...

随机推荐

  1. python 运行出现flask运行时提示出错了或者报服务器出错,ValueError: View function did not return a response

    python manage.py runserver -d

  2. Win8 Metro(C#)数字图像处理--2.61哈哈镜效果

    原文:Win8 Metro(C#)数字图像处理--2.61哈哈镜效果  [函数名称] 哈哈镜效果函数  WriteableBitmap DistortingMirrorProcess(Writea ...

  3. 蚂蚁金服招聘-JAVA资深开发工程师/专家-蚂蚁金服保险

    岗位描述: 1.协助业务方梳理业务需求,提供业务规划方案.架构设计方案: 2.负责业务系统的规划设计,制定产品的技术发展路线,完成重要业务模块及核心框架的搭建及编码实现: 3.发现和解决业务系统的技术 ...

  4. 用JavaScriptSerializer解析JSON

    引用System.Web.Extensions using System.Web.Script.Serialization; var serializer = new JavaScriptSerial ...

  5. Android零基础入门第43节:ListView优化和列表首尾使用

    原文:Android零基础入门第43节:ListView优化和列表首尾使用 前面连续几期都在学习ListView的各种使用方法,如果细心的同学可能会发现其运行效率是有待提高的,那么本期就来一起学习有哪 ...

  6. Node.js模板引擎学习----ejs

    环境:windows+node.js+express 一.安装ejs 打开cmd窗口,输入npm install ejs -g,等待下载安装完成. 二.使用 调用过程中使用路由机制和模板,路由请求地址 ...

  7. UWP入门(十)--创建、写入和读取文件

    原文:UWP入门(十)--创建.写入和读取文件 核心的 API github代码 StorageFolder 类 StorageFile 类 FileIO 类 使用 StorageFile 对象读取和 ...

  8. 命令行版扫雷(vc08)

    复制代码模拟鼠标各种按键 左键 翻开右键 标雷左右键 翻开周围 先判断当前点是否为已翻开的点 时间地雷计数器清屏 展开 大于8时不管 小于等于8时翻开本身 为0时翻开周围的输出 同雷数图雷区判断 判断 ...

  9. 用Golang让自己的电脑自动登录“上网管理”系统

    用Golang让自己的电脑自动登录 1.缘起 大天朝的网络一般都是只对某些人开放的.上行下效,同样的措施也作用在我们的教育网上.我想不出来,为什么很多领导的总有这样的恶趣味(如果做的到,他们恨不得监控 ...

  10. IIS6.0 WEB园配置

    为应用程序池创建 Web 园请注意以下几点: 一.每一个工作进程都会消耗系统资源和CPU占用率:太多的工作进程会导致系统资源和CPU利用率的急剧消耗: 二.每一个工作进程都具有自己的状态数据,如果We ...