• mvc-servlet


            网页每发一个不同的请求都需要一个servlet去响应,这样servlet很多很乱。可以只写一个servlet对请求作响应,但是servlet内部可以有很多方法,对不同请求作响应。

            如下,使用一个operation参数记录网页要求的操作,然后用switch语句转向不同函数进行处理:

    1. //设置编码方式防止汉字乱码
    2. req.setCharacterEncoding("UTF-8");
    3. //根据发送的请求中的operation字段选择方法
    4. String oper=req.getParameter("operation");
    5. if (oper==null){
    6. oper="index";
    7. }
    8. switch (oper){
    9. case "index":
    10. indexServlet(req,resp);
    11. break;
    12. case "edit":
    13. editServlet(req,resp);
    14. break;
    15. case "del":
    16. delServlet(req,resp);
    17. break;
    18. case "insert":
    19. insertServlet(req,resp);
    20. break;
    21. case "update":
    22. updateServlet(req,resp);
    23. break;
    24. default:
    25. throw new RuntimeException("illegal value for operation");
    26. }

       一、dispatcherServlet

            如果网页请求很多,那switch...case...语句会很长。使用反射改写:

    1. //获取当前类中的所有方法(反射),如果方法名和operation参数相同,就调用该方法
    2. Method[] methods=this.getClass().getDeclaredMethods();
    3. for (Method m:methods){
    4. System.out.println(m.getName());
    5. }
    6. for (Method m:methods){
    7. if(oper.equals(m.getName())){
    8. try {
    9. m.invoke(this,req,resp);
    10. return;
    11. } catch (IllegalAccessException e) {
    12. e.printStackTrace();
    13. } catch (InvocationTargetException e) {
    14. e.printStackTrace();
    15. }
    16. }
    17. }

    Notations;(1)声明的方法名要和operation值相等;(2)getDeclaredMethods才是获取自己声明的方法。

            而在实际中,会有很多servlet类,而每个之中会有很多方法。会有一个dispatcherServlet(中央控制器)来接收前端的请求,然后进行转发到各个类进行处理。可以将对某个请求的所有操作写在一个Controller里面,然后使用一个中央控制器将请求转发给处理它的Controller。

            现在src下新建一个xml,将请求和Controller的对应关系写到一个标签里面:      

    1. "1.0" encoding="UTF-8" ?>
    2. <beans>
    3. <bean id="fruit" class="com.controllers.FruitController"/>
    4. beans>

             然后建立一个中央控制器,获得该文件中的bean标签的对应关系,用一个map存储,这个map称为容器。然后接收到请求后,通过反射查询相应Controller中的所有方法。

    1. //*是通配符。表示拦截所有结尾.do的请求
    2. //通配符不能只写一个*
    3. @WebServlet("*.do")
    4. public class DispatcherServlet extends ViewBaseServlet {
    5. //创建一个Map用来存放xml的bean标签中的id和class对应。Object是其中class的实例对象
    6. Map beanMap=new HashMap();
    7. //在构造方法中解析xml配置文件
    8. public DispatcherServlet() throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException, IllegalAccessException, InstantiationException {
    9. //打开配置文件的流
    10. InputStream is=getClass().getClassLoader().getResourceAsStream("applicationController.xml");
    11. //创建一个 DocumentBuilder对象
    12. DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
    13. DocumentBuilder db=dbf.newDocumentBuilder();
    14. //创建Document对象
    15. Document doc=db.parse(is);
    16. //获取xml中所有的bean节点
    17. NodeList beanList=doc.getElementsByTagName("bean");
    18. for(int i=0;i
    19. Node beanNode = beanList.item(i);
    20. //将beanNode强转为Element,为了使用里面的getAttribute方法
    21. if (beanNode.getNodeType()==Node.ELEMENT_NODE){
    22. Element nodeElement=(Element) beanNode;
    23. String beanId=nodeElement.getAttribute("id");
    24. String beanClass=nodeElement.getAttribute("class");
    25. //运用反射得到class对应的实例对象
    26. Object beanObj=Class.forName(beanClass).newInstance();
    27. beanMap.put(beanId,beanObj);
    28. }
    29. }
    30. }
    31. @Override
    32. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    33. req.setCharacterEncoding("UTF-8");
    34. String servletPath=req.getServletPath();
    35. //把请求中的第一个/和后面的.do去掉
    36. servletPath=servletPath.substring(1,servletPath.lastIndexOf(".do"));
    37. //这就把beanMap里存放的xml文件里的对应关系给找了出来,也是找到了跟网页请求相对应的Controller对象
    38. Object beanObject=beanMap.get(servletPath);
    39. String oper=req.getParameter("operation");
    40. if (oper==null){
    41. oper="index";
    42. }
    43. //有了beanObject对象后,其对应的Controller应该有很多方法,对应执行不同的操作
    44. //通过反射查找该方法,传入参数为oper和req\resp对应的类
    45. try {
    46. //oper去匹配函数名字,后面是参数对象的class
    47. Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class,HttpServletResponse.class);
    48. if(m!=null){
    49. m.invoke(beanObject,req,resp);
    50. }else{
    51. throw new RuntimeException("oper值非法");
    52. }
    53. } catch (NoSuchMethodException e) {
    54. e.printStackTrace();
    55. } catch (IllegalAccessException e) {
    56. e.printStackTrace();
    57. } catch (InvocationTargetException e) {
    58. e.printStackTrace();
    59. }
    60. }
    61. }

      二、提取视图资源

           在经过Controller的方法处理请求后,一般方法最后会进行重定向或者对当前页面渲染。可以在中央控制器对此集中处理,让方法只返回一个字符串。这样方法可以少抛出异常,也可以不用传入response参数。如下所示:

    1. //oper去匹配函数名字,后面是参数对象的class
    2. Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class);
    3. m.setAccessible(true);
    4. if(m!=null){
    5. if(m.invoke(beanObject,req)!=null){
    6. String redirectStr=(String) m.invoke(beanObject,req);
    7. //将该str截取,只保留后面的请求名称
    8. if(redirectStr.startsWith("redirect:")){
    9. redirectStr=redirectStr.substring("redirect:".length());
    10. //重定向
    11. resp.sendRedirect(redirectStr);
    12. }else{
    13. super.processTemplate(redirectStr,req,resp);
    14. }
    15. }
    16. }else{
    17. throw new RuntimeException("oper值非法");
    18. }

    三、在中央控制器处理参数

            在Controller的每个函数中都有获取请求中函数的操作,那么可以将此直接在中央控制器处理。如下:

    1. //获取参数,先反射获取所有参数
    2. Parameter[] p=m.getParameters();
    3. //保存参数请求request中各个参数的值,所以函数的参数名要和前端发射的请求的参数名称一样
    4. Object[] parameterValue=new Object[p.length];
    5. //如果参数是request,response,session就是直接获取
    6. for (int i=0;i
    7. if(p[i].getName().equals("request")){
    8. parameterValue[i]=req;
    9. }else if(p[i].getName().equals("response")){
    10. parameterValue[i]=resp;
    11. }else if(p[i].getName().equals("session")){
    12. parameterValue[i]=req.getSession();
    13. }else {
    14. parameterValue[i] = req.getParameter(p[i].getName());
    15. }
    16. }

            

  • 相关阅读:
    一文总结 Google I/O 2023
    并发编程CompletableFuture用法
    使用定时器按键扫描数码管制作一个可存储数据的秒表
    常用js库和框架(jsPlumb)
    Hive之函数
    C++中为何需要函数
    百度实习后端开发一二三面
    【操作系统-进程】进程的概念
    【LLM之KG】CoK论文阅读笔记
    【动手学深度学习】--循环神经网络
  • 原文地址:https://blog.csdn.net/small_py_trade/article/details/127528687