网页每发一个不同的请求都需要一个servlet去响应,这样servlet很多很乱。可以只写一个servlet对请求作响应,但是servlet内部可以有很多方法,对不同请求作响应。
如下,使用一个operation参数记录网页要求的操作,然后用switch语句转向不同函数进行处理:
//设置编码方式防止汉字乱码
req.setCharacterEncoding("UTF-8");
//根据发送的请求中的operation字段选择方法
String oper=req.getParameter("operation");
if (oper==null){
oper="index";
}
switch (oper){
case "index":
indexServlet(req,resp);
break;
case "edit":
editServlet(req,resp);
break;
case "del":
delServlet(req,resp);
break;
case "insert":
insertServlet(req,resp);
break;
case "update":
updateServlet(req,resp);
break;
default:
throw new RuntimeException("illegal value for operation");
}
一、dispatcherServlet
如果网页请求很多,那switch...case...语句会很长。使用反射改写:
//获取当前类中的所有方法(反射),如果方法名和operation参数相同,就调用该方法
Method[] methods=this.getClass().getDeclaredMethods();
for (Method m:methods){
System.out.println(m.getName());
}
for (Method m:methods){
if(oper.equals(m.getName())){
try {
m.invoke(this,req,resp);
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Notations;(1)声明的方法名要和operation值相等;(2)getDeclaredMethods才是获取自己声明的方法。
而在实际中,会有很多servlet类,而每个之中会有很多方法。会有一个dispatcherServlet(中央控制器)来接收前端的请求,然后进行转发到各个类进行处理。可以将对某个请求的所有操作写在一个Controller里面,然后使用一个中央控制器将请求转发给处理它的Controller。
现在src下新建一个xml,将请求和Controller的对应关系写到一个标签里面:
然后建立一个中央控制器,获得该文件中的bean标签的对应关系,用一个map存储,这个map称为容器。然后接收到请求后,通过反射查询相应Controller中的所有方法。
//*是通配符。表示拦截所有结尾.do的请求
//通配符不能只写一个*
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
//创建一个Map用来存放xml的bean标签中的id和class对应。Object是其中class的实例对象
Map beanMap=new HashMap();
//在构造方法中解析xml配置文件
public DispatcherServlet() throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException, IllegalAccessException, InstantiationException {
//打开配置文件的流
InputStream is=getClass().getClassLoader().getResourceAsStream("applicationController.xml");
//创建一个 DocumentBuilder对象
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
//创建Document对象
Document doc=db.parse(is);
//获取xml中所有的bean节点
NodeList beanList=doc.getElementsByTagName("bean");
for(int i=0;i
二、提取视图资源
在经过Controller的方法处理请求后,一般方法最后会进行重定向或者对当前页面渲染。可以在中央控制器对此集中处理,让方法只返回一个字符串。这样方法可以少抛出异常,也可以不用传入response参数。如下所示:
//oper去匹配函数名字,后面是参数对象的class
Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class);
m.setAccessible(true);
if(m!=null){
if(m.invoke(beanObject,req)!=null){
String redirectStr=(String) m.invoke(beanObject,req);
//将该str截取,只保留后面的请求名称
if(redirectStr.startsWith("redirect:")){
redirectStr=redirectStr.substring("redirect:".length());
//重定向
resp.sendRedirect(redirectStr);
}else{
super.processTemplate(redirectStr,req,resp);
}
}
}else{
throw new RuntimeException("oper值非法");
}
三、在中央控制器处理参数
在Controller的每个函数中都有获取请求中函数的操作,那么可以将此直接在中央控制器处理。如下:
//获取参数,先反射获取所有参数
Parameter[] p=m.getParameters();
//保存参数请求request中各个参数的值,所以函数的参数名要和前端发射的请求的参数名称一样
Object[] parameterValue=new Object[p.length];
//如果参数是request,response,session就是直接获取
for (int i=0;i