写在前面:

  先来陈述一下为什么会有这样一个需求和这篇博文。

  这是公司的一个项目,我们负责前端,后台服务由其他公司负责。该系统有一个系统偏好设置模块,用户可以设置系统的背景图片等系统样式,因为这是一个比较简单的功能,所以当时没有让后台公司来实现,由自己公司的一个领导编写了一个Servlet。但是由于服务器故障被格式化之后,这个Servlet就丢失了。本来打算跟领导汇报的,但是又怕挨批评,而且这个功能也并不复杂,所以决定自己实现一下吧。但是作为一个对Java一点都不懂的我来说,还是废了不少功夫的,所以有必要将这个过程记录一下。

具体需求:

  每一个用户都可以针对该Web系统设置自己的背景图片,可以从系统预设的图片中选择,也可以自己上传新的图片。而我们需要做的就是将用户的配置信息、上传的图片保存下来,当用户下次登录时,通过配置信息加载对应的背景图片即可。

实现方案:

  方案一:

  如果将所有的用户配置信息都存放到一个文件中,那么不管在获取还是保存时,都需要解析这个文件的内容,太麻烦,而且不利于扩展。假设以后这个系统偏好设置模块,不仅可以设置背景图片,还可以设置系统的常用功能模块,那对应保存每个用户的配置信息的数据格式就变了,那么解析这个文件内容的方法也就得跟着变了。举个例子吧,假设之前文件中保存用户配置信息的数据是这样的,{"用户Id1":"url1", "用户Id2":"url2", "用户Id3":"url3", ...}。那么在扩展了功能之后,数据格式就会变成了这个样子,{"用户Id1":{"bgImage":"url1", "常用功能":"功能1, 功能2, ..."}, "用户Id2":{"bgImage":"url2", "常用功能":"功能2, 功能3, ..."}, ...},或者说变成了其他格式,不管变成了哪种格式,总之一句话,之前的那种格式已经满足不了需求了,所以解析这个文件内容的方法势必要进行改造。这就是不利于扩展的一个方面。

  方案二:

  其实我们可以根据用户Id将每一个用户的配置信息单独放到一个目录下,而每一个功能的配置信息,单独放到一个文件中。什么意思呢?其实就是这样:

  每一个用户的背景图片的配置信息都在对应用户Id文件夹下的bgImageConfig.txt文件中。这样只要给出用户Id和文件名,我们就将对应的文件内容读取直接返回给前端,无需解析文件内容。因为文件内容本身就是前端保存进来的,保存时我们也不会去关注具体保存了什么信息,只需要将内容写入文件即可。这样做还有一个好处,假设甲方增加了一个设置系统常用功能的需求,那么我们的目录就会变成这样:

  而我们的代码逻辑却不需要改变。与上面同样的道理,只要给出用户Id和文件名,我们就将文件内容直接返回给前端。我们甚至都不会去关注用户Id和文件名具体是什么,我们只需要将用户Id和文件名拼接起来,获取时,如果存在则直接读取返回;如果不存在,则返回为空或者作出提示。保存时,如果存在则直接覆盖;如果不存在,则创建然后写入内容。文件名完全可以由前端自己确定,前端保存配置信息时传递的文件名是什么,我们就保存该文件名对应的文件。获取时,只要给出对应的文件名,我们就将对应的文件内容返回即可。

  对于用户自己上传的图片,是统一放到一个目录中,还是分别放到用户Id对应的文件夹下,其实也是有讲究的。假设统一放到一个目录中,那假如两个用户上传的图片是不一样的,但是恰好文件名是一样的,那之前的图片岂不是会被覆盖了?所以还是分别放到用户Id对应的文件夹下比较好。

技术点:

  1、Servlet

    虽然是Java小白,但是基本的Servlet还是了解的,但是也仅仅停留在创建一个Servlet,测试一下GET、POST请求而已。

  2、Java上传文件

    这里是通过commons-fileupload-1.3.1.jar和commons-io-2.5.jar来实现的,代码是从网上找的,具体原理还是不太明白,这里就不贴代码了,等到最后记录一下项目的地址。

    还有一点需要注意的是,上传文件时的参数获取和普通的GET、POST请求的参数获取,还是不一样的。我们需要获取文件流,判断文件流是不是非文件域fileItem.isFormField(),如果是非文件域,则通过fileItem.getFieldName()获取参数名,通过new String[]{Streams.asString(fileItem.getInputStream())}获取参数值。

    另外需要注意的一点是,我们需要获取文件的上传路径,这里我们是通过request.getSession().getServletContext().getRealPath("")得到工程目录所对应的路径的,然后执行创建文件夹、写文件等操作。我们还需要返回前端一个可访问的Web路径,当然不能是功能目录所对应的绝对路径,这样前端是访问不到的。这里我们是通过request.getRequestURL()获取前端的请求路径,然后和前面保存的上传路径拼接起来的,这部分功能参考了这里

    关于获取文件的上传路径和返回前端一个可访问的Web路径,总感觉自己的做法太麻烦,抽空需要请教一下有没有简便的做法。

  3、Java的文件操作

    通过实现这么一个功能,对File类有了一个基本的认识。该类的对象可以代表一个具体的文件或文件夹。通过该类,可以实现创建文件夹mkdir()、mkdirs(),创建文件createNewFile(),判断文件或文件夹是否存在exists()等。这里参考的是火之光Java写入文件的几种方法

总结:

  虽然这个功能是做通了,但是还是有好多不明白的地方,还是应该再接着研究的,否则下次还是不知道怎么用。

  项目地址:https://github.com/Youwanwu/CloudServer.git

Servlet之保存用户偏好设置简单功能的实现的更多相关文章

  1. Android 保存用户偏好设置

    很多情况下都允许用户根据自己的习惯和爱好去设置软件,而我们需要保存这些设置,可以用一个专业保存用户偏好的类:SharedPreferences. 这个类是实现方法其实也就是创建和修改 XML 文件, ...

  2. 16_采用SharedPreferences保存用户偏好设置参数

    按钮事件 <Button android:id="@+id/button" android:layout_width="wrap_content" and ...

  3. 黎活明8天快速掌握android视频教程--16_采用SharedPreferences保存用户偏好设置参数

    SharedPreferences保存的数据是xml格式,也是存在数据保存的下面四种权限: 我们来看看 我们来看看具体的业务操作类: /** * 文件名:SharedPrecences.java * ...

  4. 【Qt官方例程学习笔记】Application Example(构成界面/QAction/退出时询问保存/用户偏好载入和保存/文本文件的载入和保存/QCommandLineParser解析运行参数)

    The Application example shows how to implement a standard GUI application with menus, toolbars, and ...

  5. Android之使用SharedPreferences保存用户偏好参数

    在Android应用中,我们常需要记录用户设置的一些偏好参数,,此时我们就需要用SharedPreferences和Editor将这些信息保存下来,在下次登录时读取. SharedPreference ...

  6. SharedPreferences保存用户偏好参数

    package com.example.administrator.myapplication; import android.content.Context; import android.cont ...

  7. iOS开发--应用设置及用户默认设置【2、读取应用中的设置】

            在上一节中,我们通过探讨应用的系统设置的基本功能,了解运用bundle捆绑包以及plist文件的基本开发.用户能够使用设置应用来声明他们的偏好设置,那么我们怎样去调用用户所设置的参数呢 ...

  8. iOS开发--应用设置及用户默认设置——转载

    [链接]iOS开发--应用设置及用户默认设置[1.bundlehttp://www.jianshu.com/p/6f2913f6b218 在iphone里面,应用都会在“设置”里面有个专属的应用设置, ...

  9. iOS: 偏好设置的详解和使用

    偏好设置的详解: 用途:主要用来存储用户系统的设备信息,但有的时候也可以在程序的任何地方用来存储数据,作为全局数据来访问,例如视图切换需要进行登录时. 偏好设置的写入: •很多iOS应用都支持偏好设置 ...

随机推荐

  1. 提高Java代码质量的Eclipse插件之Checkstyle的使用详解

    提高Java代码质量的Eclipse插件之Checkstyle的使用详解 CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具.它能够自动化代 ...

  2. WCF服务承载

    WCF服务承载(笔记)   自托管(也做自承载) 承载 WCF 服务最灵活.最便捷的方法就是进行自承载.要能够自承载服务,必须满足两个条件.第一,需要 WCF 运行时:第二,需要可以承载 Servic ...

  3. 嵌入式Linux学习(二)

    嵌入式系统和通用计算机的主要区别 嵌入式系统是指以应用为中心,以计算机技术为基础,软件硬件可裁剪,适应应用系统对功能.可靠性.成本.体积.功耗严格要求的专用计算机系统. 嵌入式系统主要由嵌入式微处理器 ...

  4. 链方法[C# 基础知识系列]专题三:如何用委托包装多个方法——委托链

    最近研究链方法,稍微总结一下,以后继续补充: 弁言: 上一专题分析了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的分析都是委托只是封装一个方法,那委 ...

  5. bzoj 1430: 小猴打架 -- prufer编码

    1430: 小猴打架 Time Limit: 5 Sec  Memory Limit: 162 MB Description 一开始森林里面有N只互不相识的小猴子,它们经常打架,但打架的双方都必须不是 ...

  6. 机器学习( Machine Learning)的定义

    关于机器学习有两个相关的定义: 1)给计算机赋予没有固定编程的学习能力的研究领域. 2)一种计算机的程序,能从一些任务(T)和性能的度量(P),经验(E)中进行学习.在学习中,任务T的性能P能够随着P ...

  7. c语言中细节注意(初级)

    /* 编写如下函数,不使用下标运算符,返回字符串str中字符c的个数 (若不存在则为0). */ #include <stdio.h> int str_chnum(const char * ...

  8. 一键强制修改任意Mysql数据库的密码,修改任意环境Mysql数据库。

    本文采用我软件里面的内置改密功能,可以一键强制修改Mysql数据库的密码, 在修改过程中,会强制干掉Mysql主程序,修改完成后重新启动Mysql就可以了. 首先讲解如何一键强制修改PHPWAMP自身 ...

  9. UOJ#117. 欧拉回路

    #117. 欧拉回路 题目描述 有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次. 一共两个子任务: 这张图是无向图.(50分) 这张图是有向图.(5 ...

  10. codevs1002搭桥(prim)

    题目描述: 这是道题题意有点迷(或者是我语文不好),但其实实际上求的就是图中连通块的个数,然后在连通块与连通块之间连边建图跑最小生成树.但是--这个图可能是不连通的--求桥的数量和总长 于是我立刻想到 ...