写在前面:

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

  这是公司的一个项目,我们负责前端,后台服务由其他公司负责。该系统有一个系统偏好设置模块,用户可以设置系统的背景图片等系统样式,因为这是一个比较简单的功能,所以当时没有让后台公司来实现,由自己公司的一个领导编写了一个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. Entity Framework:如果允许模型处于非法状态,在某些场景下,记得清空DbContext

    Entity Framework:如果允许模型处于非法状态,在某些场景下,记得清空DbContext 背景 之前写过两篇文章介绍模型的合法性: DDD:关于模型的合法性,Entity.IsValid( ...

  2. C#基础之方法和参数

    C#基础之方法和参数 接上一篇<C#基础之类型和成员基础以及常量.字段.属性> 实例方法.静态方法 C#中的方法分为两类,一种是属于对象(类型的实例)的,称之为实例方法,另一种是属于类型的 ...

  3. struts2对ognl表达式的使用(配图解加讲解)

    ognl它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对Java对象图进行导航. 先看一张示意图 如果是下面的除了第一种valueStack的下面几 ...

  4. swift 动态获取label宽度或高度

    func getLabHeigh(labelStr:String,font:UIFont,width:CGFloat) -> CGFloat { let statusLabelText: NSS ...

  5. java BigInteger源码学习

    转载自http://www.hollischuang.com/archives/176 在java中,有很多基本数据类型我们可以直接使用,比如用于表示浮点型的float.double,用于表示字符型的 ...

  6. [APUE]进程控制(中)

    一.wait和waitpid函数 当一个进程正常或异常终止时会向父进程发送SIGCHLD信号.对于这种信号系统默认会忽略.调用wait/waidpid的进程可能会: 阻塞(如果其子进程都还在运行); ...

  7. window.onload多个共存 - 借鉴jQuery.noConflict的思路

    一.背景  window.onload方法只能存在一个,如果多次赋值给window.onload,则后者会覆盖前者. 二.浅谈jQuery.noConflict的实现方式 1)源代码 // 简化抽离出 ...

  8. Linux编程之UDP SOCKET全攻略

    这篇文章将对linux下udp socket编程重要知识点进行总结,无论是开发人员应知应会的,还是说udp socket的一些偏僻知识点,本文都会讲到.尽可能做到,读了一篇文章之后,大家对udp so ...

  9. 使用TypeScript开发ReactNative应用的简单示例

    最近小小尝试了下 ReactNative + TypeScript 开发APP,爬了无数坑之后总算弄出来个结果,重要的地方记录下,后面会附上示例代码: 1.开发工具的选择 windows 平台我接触的 ...

  10. 【转】【WebService】.NET C# 创建WebService服务

    Web service是一个基于可编程的web的应用程序,用于开发分布式的互操作的应用程序,也是一种web服务 WebService的特性有以下几点: 1.使用XML(标准通用标记语言)来作为数据交互 ...