在原项目中,对文件上传的处理并不是使用Spring的MultipartResolver,而是使用自定义的MultiPartFilter和HttpServletRequestWrapper结合来进行处理。
MultiPartFilter是一个定义在web.xml中的<filter>,原理是通过判断HttpServletRequest中的contentType是否包含”multipart/form-data”,若代码中包含此字符品,则表明是一个File Upload请求,就使用JakartaMultiPartRequest来对HttpServletRequest对其进行包装。
其代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| public class MultiPartFilter extends GenericFilterBean {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String content_type = request.getContentType();
if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {
JakartaMultiPartRequest jakartaMultiPartRequest = new JakartaMultiPartRequest(request,
getFilterConfig().getInitParameter("saveDir"), Integer.valueOf(
getFilterConfig().getInitParameter("maxUploadSize")).intValue());
request = jakartaMultiPartRequest;
}
filterChain.doFilter(request, servletResponse);
}
} |
JakartaMultiPartRequest类继承自HttpServletRequestWrapper,在其构造方法中,我们对Request进行分析,并且保存用户上传的文件,将文件名等信息放到Request的attribute中,从而在后续的代码中可以对上传的文件进行处理。
但在后来客户进出的对产品图片处理的新需求中,因为JakartaMultiPartRequest的问题,没有办法满足我们的要求,所以考虑到使用Spring的MultipartResolver来进行上传处理,但之前的代码不能再进行改动,否则所有处理文件上传的Controller必须更改,代价很大。但如果在Spring中进行配置MultipartResolver的配置后,发现我们旧的文件上传代码都失效了,无法上传文件。
(阅读全文……)
File Upload, Multipart, Spring
折腾了两天,终于在JBoss Seam中搞定了JSF Converter。
在这个程序中,产品(Product)和分类(Category)是多对多的关系,关系维护方为产品,在创建产品时,允许选择多个分类,因为Product.categories是一个List属性,同时产品选择<select />标签也是由从Action中查询出来的所有Category的List,所以在页面上,需要在页面渲染、用户提交后的category进行转换。
显示时,我们以Category.id为<option />的value值,而Category.title为label。
Entity如下(省略setter和getter):
Category.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| @Entity
@Table(name = "category")
public class Category extends BaseEntity {
@Id
@GeneratedValue
@Column(name = "id", unique = true, nullable = false, length = 10)
private Integer id;
@Column(name = "title")
@NotNull
@Length(min = 4, max = 64, message = "{invalid.length}")
private String title;
@ManyToMany(mappedBy = "categories")
private List<product> products = new ArrayList</product><product>();
}
</product> |
(阅读全文……)
Converter, JBoss Seam, JSF
享元模式的宗旨:通过共享来为大量的细粒度对象提供有效支持。
避免大量拥有相同类型的小类(细粒度,小类中的不可变部份)的开销(如耗费内存),使所有客户代码共享一个实例(元类)。
怎么使用?(以人力资源系统中的公司员工为例):
一般来说,在需要对某个员工进行访问的时候,我们都会new一个员工类,如果两个客户代码同时访问同一个员工,则会产生两个相同(或部份相同)的同一员工实例,这样,对于一个员工来说,内存中就可能有该员工的多个实例存在,如果一个企业有10000个员工,那内存中实际的员工实例可能就不止10000个。在这种情况下,我们就可以用享元模式来解决这个问题。
(阅读全文……)
Design Pattern, Flyweight, Java
模板方法模式的目的就是在一个方法中实现一个算法,并将算法中某些步骤的定义推迟,从而使得其他类可以重新定义这些步骤。
在编写一个方法的时候,考虑到算法的某些步骤可能会有不同的实现方式,我们可能会首先定出算法的框架。这样,在定义方法的时候,我们可以将某些步骤定义为抽象方法,或者是将它们定义为存根方法,也可以将它们定义为某个单独接口中的方法,这就是模板方法模式的实现。
模板方法的典型例子就是排序。java.util.Collections类将sort()方法定义为一个模板方法,而将其中的比较交给用户来实现,sort()方法所接受的List中的对象需要实现Comparator接口,这就是将实际算法推迟并交给其它类来实现的模板方法模式。
(阅读全文……)
Design Pattern, Java, Template Method
并不是能创建并返回一个新的对象的方法都是工厂方法模式的实例。
工厂方法模式不仅要求有一个能够创建新对象的方法,还要求能够使得客户代码无需了解应该具体实例化哪个类。工厂方法模式通常会包含有若干个类,这些类实现了相同的操作,返回了相同的抽象类型,然而,这些类的操作在内部实际上实例化了不同的类,不过这些类都实现了上述抽象类型。
工厂方法模式的特征:
1. 该方法创建了一个新的对象。
2. 该方法的返回类型为一个抽象类或接口。
3. 有若干个类实现了上述抽象类或接口。
比如我们要实现一个在线客户服务系统,若客服人员在线的时候,客户提交的问题将会直接传送给客服人员;若客服人员不在线,则将客户提交的问题发送至客服信箱。
(阅读全文……)
Design Pattern, Factory Method, Java
观察者模式的宗旨:在多个对象之间定义一个一对多的关系,当一个对象状态改变的时候,其他所有的依赖于这个对象的对象能够得到通知,并自动更新。
观察者模式在Swing中得到了广泛应用。当客户单击按钮时,程序中许多对象都会对此做出反应。在Swing中,关注Swing组件变化的类被称为“监听器”,这就是观察者模式的应用。
为了支持观察者模式,Java类库中的java.util包中提供了Observable类和Observer接口。
我们现在举一个例子来说明观察者模式。
在网上商店的应用中,如果我们希望产品的名称被更改了后,系统会自动在控制台打印新名称,则就可以使用观察者模式。此时,产品类Product就需要继承Observable类,产品观察者类NameObserver则需要实现Observer接口。
(阅读全文……)
Design Pattern, Java, Observer
单体模式的宗旨就是:使一个类只有一个实例。
我们可以将类的constructor的可见性设置为私有来避免创建多个实例。当其他类调用该类的时候,我们可以利用getInstance()之类的方法来返回给调用者该类的实例。
比如:
1
2
3
4
5
6
7
8
9
| private Factory factory = null;
public static Factory getFactory() {
if (factory == null) {
factory = new Facotry();
}
return factory;
} |
上面的例子实现了单体模式,但如果在多线程环境中采用此方式,仍然可能产生多个实例,最好的办法,用synchronized来控制Factory实例的生成。
(阅读全文……)
Design Pattern, Java, Singleton
当我们准备实现某个指定接口的时候,我们可能会发现现存的类已经提供了这种功能,只是方法名不同而已。这个时候,我们可以通过利用适配器模式来修改这个现存的类与外界交互的接口,从而使之满足用户的要求。
适配器模式的宗旨就是,保留现有的类所提供的服务,修改其接口,从而达到客户期望。
类适配器:

类适配器
(阅读全文……)
Adapter, Design Pattern, Java
类的接口,就是该类允许其他类对象访问的方法和域的集合。一个类实现了某个接口,通常意味着该类的方法将会执行接口方法名表示的操作,遵循接口方法的代码注释和其他相关文档的要求。而类的实现就是位于这些方法体内的代码。
比如:
1
2
3
| interface Login {
boolean login(String name, String password);
} |
需要注意的地方:
1. 接口的方法总是抽象的,无论是否显式地声明。
2. 接口的方法总是公共的,无论是否显式地声明。
3. 接口的可见性受限于其所在的包,因为Login没有显式地声明为public,所以其在包内可见。
4. 一个接口可以扩展另一个接口。比如List接口扩展了Collection。
5. 接口可以不包含方法。不包含方法的接口称为“标记”接口。比如Cloneable接口。
6. 接口不能声明实例域,不过可以通过声明static和final修饰的域来声明常量。
Design Pattern, Interface, Java
1. 索引按顺序排列存储
2. 选择索引
搜索的索引列,不一定是所要选择的列。出现在ON,WHERE和GROUP BY后的列适合作索引。
使用惟一索引
对于惟一值的列,索引的效果最好。例如:存放年龄的列具有不同值,所以很容易区分各行;而用来记录性别的列,只有’M'和’F',不论搜索哪个值,都会得出大约一半的行,所以对其进行索引没有多大用途。
使用短索引
如果对字符串类型的列进行索引,应该指定一个前辍长度。比如一个varchar(200)的列,最好指定索引为前10个或20个字符内。(短的索引节省存储空间,并可能使查询更快)
利用最左前辍
在创建一个包含n列的索引时,实际上是创建了MySQL可以使用的n个索引。
多列索引可起几个索引的作用,因为可利用索引中最左边的列来匹配行。这样的列的集称为最左前辍。
比如在一个表中的state, city和zip三个列上创建索引,那么索引中的行是按state/city/zip的次序存放的。因此,索引中的行也会自动按state/city的顺序和state的顺序来存放。所以,该索引可以用来搜索下列的列的组合:
state/city/zip
state/city
state
(阅读全文……)
MySQL, Query Optimize