在上一节的程序中有一个严重的问题,ServletProcessor.process()方法:
try {
servlet=(Servlet) myClass.newInstance();
servlet.service((ServletRequest)request, (ServletResponse)response);
}
在servlet中,public void service(ServletRequest req, ServletResponse res)接受
servlet.service((ServletRequest)request, (ServletResponse)response)传过来的参数,
,因此,在service方法中可以通过向下转型的方法,将req和res分别转型为Response和Request,这样就可以访问到Request和Response中自己特有的公有方法,这是不安全的。按照servlet的设计,在service()方法中只能访问ServletRequest req接口和ServletResponse接口中已经声明的方法。
下面将简单演示这种不安全的做法:
在Request类中添加一个测试方法
public void Test(){
System.out.println("这个方法是Request类特有的,不能再servlet中进行调用");
}
在Response类中添加一个测试方法
public void Test(){
System.out.println("这个方法是Response类特有的,不能再servlet中进行调用");
}
在MyFirstServlet类中通过向下转型调用上面两个测试方法:
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
PrintWriter printWriter=res.getWriter();
System.out.println("servlet开始执行");
printWriter.println("Hello,Servlet");
/***********************************/
Request re=(Request) req;//向下转型为Request,可以调用Request中的公有方法和属性
Response rs=(Response) res;//向下转型为Response,可以调用Response中的公有方法和属性
re.Test();
rs.Test();
/***********************************/
}
在浏览器中输入http://127.0.0.1:8888/servlet/MyFirstServlet后,控制台显示如下:
Request和Response中特有的方法被成功调用。
为了很好的解决这个问题,那么就需要使用外观类,将Request和Response自己的方法进行屏蔽(或者说私有化),这样在其它类中就不能调用它们自己的方法,UML关系简图如下:
需要上一节的基础上增加两个类,RequestFacade类和ResponseFacade类。另外,ServletProcessor类也需要做一点小的修改
=====================分割线=====================
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class RequestFacade implements ServletRequest {
private ServletRequest request=null;//包装类的所有方法都调用request对应的方法来完成
public RequestFacade(ServletRequest request){
this.request=request;
}
@Override
public AsyncContext getAsyncContext() {
return request.getAsyncContext();
}
@Override
public Object getAttribute(String name) {
return request.getAttribute(name);
}
@Override
public Enumeration<String> getAttributeNames() {
return request.getAttributeNames();
}
@Override
public String getCharacterEncoding() {
return request.getCharacterEncoding();
}
@Override
public int getContentLength() {
return request.getContentLength();
}
@Override
public String getContentType() {
return request.getContentType();
}
@Override
public DispatcherType getDispatcherType() {
return request.getDispatcherType();
}
@Override
public ServletInputStream getInputStream() throws IOException {
return request.getInputStream();
}
@Override
public String getLocalAddr() {
return request.getLocalAddr();
}
@Override
public String getLocalName() {
return request.getLocalName();
}
@Override
public int getLocalPort() {
return request.getLocalPort();
}
@Override
public Locale getLocale() {
return request.getLocale();
}
@Override
public Enumeration<Locale> getLocales() {
return request.getLocales();
}
@Override
public String getParameter(String name) {
return request.getParameter(name);
}
@Override
public Map<String, String[]> getParameterMap() {
return request.getParameterMap();
}
@Override
public Enumeration<String> getParameterNames() {
return request.getParameterNames();
}
@Override
public String[] getParameterValues(String name) {
return request.getParameterValues(name);
}
@Override
public String getProtocol() {
return request.getProtocol();
}
@Override
public BufferedReader getReader() throws IOException {
return request.getReader();
}
@Override
public String getRealPath(String path) {
return request.getRealPath(path);
}
@Override
public String getRemoteAddr() {
return request.getRemoteAddr();
}
@Override
public String getRemoteHost() {
return request.getRemoteHost();
}
@Override
public int getRemotePort() {
return request.getRemotePort();
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
return request.getRequestDispatcher(path);
}
@Override
public String getScheme() {
return request.getScheme();
}
@Override
public String getServerName() {
return request.getServerName();
}
@Override
public int getServerPort() {
return request.getServerPort();
}
@Override
public ServletContext getServletContext() {
return request.getServletContext();
}
@Override
public boolean isAsyncStarted() {
return request.isAsyncStarted();
}
@Override
public boolean isAsyncSupported() {
return request.isAsyncSupported();
}
@Override
public boolean isSecure() {
return request.isSecure();
}
@Override
public void removeAttribute(String name) {
request.removeAttribute(name);
}
@Override
public void setAttribute(String name, Object o) {
request.setAttribute(name, o);
}
@Override
public void setCharacterEncoding(String env)
throws UnsupportedEncodingException {
request.setCharacterEncoding(env);
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
return request.startAsync();
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest,
ServletResponse servletResponse) throws IllegalStateException {
return request.startAsync(servletRequest, servletResponse);
}
}
=====================分割线=====================
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
public class ResponseFacade implements ServletResponse{
private ServletResponse response;//包装类的所有方法都有response对应的方法完成
public ResponseFacade(ServletResponse response){
this.response = response;
}
@Override
public void flushBuffer() throws IOException {
response.flushBuffer();
}
@Override
public int getBufferSize() {
return response.getBufferSize();
}
@Override
public String getCharacterEncoding() {
return response.getCharacterEncoding();
}
@Override
public String getContentType() {
return response.getContentType();
}
@Override
public Locale getLocale() {
return response.getLocale();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return response.getOutputStream();
}
@Override
public PrintWriter getWriter() throws IOException {
return response.getWriter();
}
@Override
public boolean isCommitted() {
return response.isCommitted();
}
@Override
public void reset() {
response.reset();
}
@Override
public void resetBuffer() {
response.resetBuffer();
}
@Override
public void setBufferSize(int size) {
response.setBufferSize(size);
}
@Override
public void setCharacterEncoding(String charset) {
response.setCharacterEncoding(charset);
}
@Override
public void setContentLength(int len) {
response.setContentLength(len);
}
@Override
public void setContentType(String type) {
response.setContentType(type);
}
@Override
public void setLocale(Locale loc) {
response.setLocale(loc);
}
}
=====================分割线=====================
ServletProcessor类只需新构建RequestFacade和ResponseFacade类,并将其引用作为参数传入servlet.service()方法中
Servlet servlet=null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
/**
* servlet实例化
*/
servlet=(Servlet) myClass.newInstance();
/**
* 调用servlet的service()方法
*/
servlet.service((ServletRequest)requestFacade, (ServletResponse)responseFacade);//传入包装类
}
程序经过上述修改后,在servlet中便不能再访问Request和Response中自己的方法了,同时运行结果也和上一节相同。