~~继承方式实现对目标对象的方法增强
在我们日常的开发中,可能会遇到这样的问题:某一个类的某一个方法在时候时有局限性,不符合我们的要求,
但是这个类可能在框架中,可能在服务器软件中,不由我们自己去创建,这个时候,无论是装饰设计模式还是动态代理
或者cglib的方式都不太好用,在这种情况下我们可以通过配置的方式,让框架在生成这个类的时候时创建的我们自己
创建的一个类,这样该类的对象还是有框架创建,但是某一个方法的实现却更符合我们的要求。下面就以tomcat服务器
在处理要访问的图片的路径中含有中文导致无法访问这个问题为例,用继承的方式去实现对其解决。
1.首先我们先要分析一下这个问题出现的原因:
我们知道我们每一次向浏览器发出一次请求的时候,返回的页面中可能包含图片。\”< img src=”/image/01_logo.jpg”>” 这种标签。当浏览器解析到这个地方的时候, 它会自动的向服务器再次发送一个请求,这个请求就是这张图片中的src路径,在这里多说依据,很多同学搞不明白在很多标签中,有src属性,有的是href属性 这两种属性有什么区别,他们之间的区别就是,这个资源时浏览器自己发送请求,还是用户在点击对应标签时,浏览器再发出请求。当浏览器解析到src属性时,自动的向 服务器发送一次这个src中路径的请求,而解析到href属性时则不会自动请求。例如\”< a href=”/jsp/index.jsp”>”这个地址,只有用户点击的时候,浏览器才回去访问。 好了,言归正传,当浏览器解析到图片的src属性时,浏览器自动发送请求。这个请求的请求行中就是src中的地址。好了,下一问题就是,当我们的服务器接收到这个请求时会怎样处理这个请求。我们的服务器会先去在项目和服务器的web.xml文件中按照‘完全匹配’, ’目录匹配‘,’后缀名’匹配的方式去匹配请求行中的地址。如果都匹配不到,则交给缺省 servlet去处理这个请求,缺省servlet一般处理的都是静态资源。按照上面所说,我们的图片的请求肯定在这两个xml文件中匹配不上,就会交给我们的缺省servlet去处理。 最后一个问题,就是缺省servlet怎样处理这些请求。具体的过程很复杂,也不是我们要将的重点, 我们只关注,我们的图片请求在传递到缺省servlet后怎么去找到它的地址。
protected String getRelativePath(HttpServletRequest request) {
// IMPORTANT: DefaultServlet can be mapped to '/' or '/path/*' but always
// serves resources from the web app root with context rooted paths.
// i.e. it can not be used to mount the web app root under a sub-path
// This method must construct a complete context rooted path, although
// subclasses can change this behaviour.
// Are we being processed by a RequestDispatcher.include()?
if (request.getAttribute(
RequestDispatcher.INCLUDE_REQUEST_URI) != null) {
String result = (String) request.getAttribute(
RequestDispatcher.INCLUDE_PATH_INFO);
if (result == null) {
result = (String) request.getAttribute(
RequestDispatcher.INCLUDE_SERVLET_PATH);
} else {
result = (String) request.getAttribute(
RequestDispatcher.INCLUDE_SERVLET_PATH) + result;
}
if ((result == null) || (result.equals(""))) {
result = "/";
}
return (result);
}
// No, extract the desired path directly from the request
String result = request.getPathInfo();
if (result == null) {
result = request.getServletPath();
} else {
result = request.getServletPath() + result;
}
if ((result == null) || (result.equals(""))) {
result = "/";
}
return (result);
}
上面的函数就是缺省servelt处理我们请求的函数,它会在我们的request对象中获取到我们要访问
的真是路径,这个时候就有出现了一个我们文章开头的问题,如果图片的地址中含有中文,这个时候
会出现什么情况。
上面的返回值就是在执行一个含有中文路径的图片请求时这个函数的返回值。
如果返回这样的值,在我们的服务器端是肯定匹配不到图片的资源的。
如果你知道上面这个问题出现的原因,那么可以跳过这一段,这一段是为那些对出现乱码感到困惑
的同学准备的。
首先解释一下为什么这里会出现乱码:乱码在我们的开发中经常遇到,(如果不想遇到的话,就去学习一下go
语言,用它开发是不会遇到乱码问题的)其根本的原因就是我们在对字节流到字符流,从字符流到字节流
这两个转换之间用的字符集不相同导致的。我们应该确认的一点就是,tomcat服务器是外国人开发的,他们
不会去在乎中国人的开发习惯和语言,所以tomcat默认的编码和解码就是iso8859-1。我们知道,这个字符集是
不支持中文的,也就是说你用他根本就传输不了中文。我们在浏览器端的请求头默认是经过utf-8编码,
在服务器对其封装成request对象时,如果要取出其中的请求路径,它默认经过了iso8859-1解码,这就出现了
乱码,那怎么解决乱码问题呢?我们可以通过将得到的字符串重新用iso8859-1编码,返回到接受到的原始的
字节流的状态,然后再用我们的utf-8解码,这样就能解决乱码问题了,其代码实现就是下面这一行
relativePath = new String(relativePath.getBytes("iso8859-1"),"utf-8")
已经解决了中文乱码问题,那我们就应该回到我们今天问题的中心,怎样让这个默认的缺省servlet去执行
我想要的代码,而不是它自己的。
我们学习过javaWEB基础,肯定知道,当我们配置一个servlet的url-pattern为/时,他就会拦截所有的请求,
也就是实现说,我们写一个servelt将他的url-pattern设置为/,这个servlet就代替tomcat默认的缺省servlet
成为我们这个系统的缺省servlet。
那我们应该怎样却写一个servelt,既能处理所有的请求,又能处理我们想要的这一段程序到,答案就是:我们
的缺省servlet继承系统的缺省servlet,org.apache.catalina.servlets.DefaultServlet,具体代码如下
package com.itcast.demo;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.servlets.DefaultServlet;
/**
* Servlet implementation class MyServlet
*/
public class MyServlet extends DefaultServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// TODO Auto-generated method stub
super.doGet(request, response);
}
protected String getRelativePath(HttpServletRequest request) {
// TODO Auto-generated method stub
String relativePath = super.getRelativePath(request);
try {
relativePath = new String(relativePath.getBytes("iso8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return relativePath;
}
}
项目的WEB-INF中web.xml的配置如下:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.itcast.demo.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
这样我们就通过继承的方式增强了系统的缺省servelt中的getRealPath这个方法,解决了图片路径中包含中文
导致无法访问的问题。当然,继承方式实现对目标对象的方法增强是很低级的,也很笨重,但是在某些我们
无法修改这个对象的创建的时机的特定情况下,还是有一点作用的,后面还有三种增强方法的方式,让我们慢慢
学习,共同进步。