zoukankan      html  css  js  c++  java
  • 反思java web的发展

    本来网站都是一个个静态HTML的,但很快我们就不满足于这样了。动态网页应运而生。
    一开始是Servlet。其代码类似于下面这样。
    主要是Java代码,然后用out一点一点输出HTML代码。
    当然代码无比丑陋,且美工人员几乎不能理解这样的代码。
    out.write("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    ");
    out.write("<html>
    ");
    out.write("<head>
    ");
    out.write("<title>首页</title>
    ");
    out.write("</head>
    ");
    out.write("<body>
    ");
    out.write("Hello, " + new Date().toLocalString
    out.write("</body>
    ");
    out.write("</html>
    ");
    

    所以,很快JSP应运而生。其代码类似于下面这样。
    JSP很像是正常的HTML代码中,藏了一些Java代码。
    就这样Java Web技术疯狂发展了。
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <title>首页</title>
    </head>
    <body>
    
    	<ss:a label="首页" href="/index.jsp" />
    	<ss:a label="登入" href="/login.jsp" />
    	<ss:a label="注册" href="/register.jsp" />
    	<ss:a label="登出" href="/logout.do" />
    	<hr />
    
    	<jsp:include page="/include/jsp/datetime.jsp" />
    	<%
    		String user = (String) session.getAttribute("user");
    		if (user != null && user.length() > 0) {
    			out.println("Welcome, <b>" + user + "</b>! You are logged in.");
    		}
    	%>
    
    </body>
    </html>
    

    随着实际Web应用的使用越来越广泛,Web应用的规模也越来越大,开发人员发现动态Web应用的维护成本也越来越大,即使只需要修改该页面的一个简单按钮文本,或者一段静态的文本内容,也不得不打开混杂的动态脚本的页面源文件进行修改——这是一种很大的风险,完全有可能引入新的错误。

    MVC模式的诞生

    这时候,人们意识到:单纯使用JSP页面充当过多角色是相当失败的选择,这对于后期的维护相当不利,慢慢地开发人员开始在Web开发中使用MVC模式。

    Java阵营慢慢的发展出了适合Java Web开的的MVC模式。(看下图)
    使用JSP作为视图,Servlet作为控制器,JavaBean作为模型。
    通过合理的分层,使得Java程序员更能驾驭大型网站的开发。


    使用MVC模式有一个问题,Servlet中获取到的数据如何传递到视图层呢?
    //一般采取这种办法
    //在Servlet中将结果设置到request对象当中。
    request.setAttribute("result", result);
    
    //在JSP中通过request对象来获取。
    <% Object result = request.getAttribute("result"); %>
    

    可是JSP既然是视图层,如果嵌入太多JAVA代码的话,对于美工的工作相当不利。
    一般来说视图层是不允许使用<% %>来嵌入JAVA代码的。
    可是视图层也确实需要负责进行一些逻辑判断,来动态输出页面。

    当然,Java提供了一个办法,使用“自定义标签”,和“EL表达式”。
    <table>
        <th>
          <td>序号</td>
          <td>姓名</td>
          <td>性别</td>
          <td>年龄</td>
          <td>电话</td>
        </th>
      <c:forEach var="item" items="${request.list}">
        <tr>
          <td>${item.id}</td>
          <td>${item.name}</td>
          <td>${item.sex}</td>
          <td>${item.age}</td>
          <td>${item.phone}</td>
        </tr>
      </c:forEach>
    </table>
    

    视图层的问题看起来不太大,现在来看看控制层。
    //首先,你需要在Web.xml中进行配置
    <servlet>
      <servlet-name>LoginServlet</servlet-name>
      <servlet-class>com.tee.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>LoginServlet</servlet-name>
      <url-pattern>/Login</url-pattern>
    </servlet-mapping>
    

    //然后,需要编写一个继承自HttpServlet类的Servlet。
    package com.tee.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class RegisterServlet extends HttpServlet {
    
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    		String username = request.getParameter("username");
    		String password = request.getParameter("password");
    		if (UserDao.validate(username, password)) {
    			request.getSession.setAttribute("user", username);
    			response.setContentType("text/html; charset=utf-8");
    			response.sendRedirect("/index.jsp");
    		} else {
    			ServletContext sc = getServletContext();
    			RequestDispatcher rd = sc.getRequestDispatcher("/login.jsp");
    			request.setAttribute("errMsg", "login failure");
    			rd.forward(request, response);
    		}
    	}
    	
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    		doGet(request,response);
    	}
    }
    

    这样一来,首先Web.xml会越来越大,越来越难以维护。
    且修改Web.xml的风险很大,只要一个错误,整个网站都有可能无法访问。

    上面的例子没有进行传入参数的检验,如是否为空,是否有是规定长度,是否是规定的字符。也没有涉及到参数转换,如转换成Date类型,转换成int类型。一旦发生错误又该如何传递给前端,前端又该如何接受错误信息,如何展示出来。

    因为Servlet必须继承自HttpServlet,且内部与Servlet Api高度耦合,不但难以测试,而且难以重用。更不要说我们总是需要书写大量与业务逻辑无关的代码。

    MVC框架的诞生
    同样的代码写两次就是罪过,所以我们需要什么东西来让我们解放出来。
    很快人们就发展出了一套MVC框架,特别是适合于Java Web的MVC框架。

    MVC框架能帮我们做什么?
    这里引用“四刘”的回答:
    框架和普通库的几点区别里,我认为最重要的一点是控制反转。
    框架规定了开发者写哪些代码/不写哪些代码,怎么写代码——这就是框架主要解决的问题。
    MVC框架实现了MVC模式。什么意思?
    意思是只要你根据框架的要求填充代码,你就能够很简单的实现MVC模式。

    谁来响应用户请求?框架可能告诉你,Action就是用来响应用户请求的。
    不用再继承HttpServlet,代码中也可以完全脱离Servlet Api。复用度高,可单元测试。

    谁负责生成响应界面?框架可能告诉你,可以用一个JSP文件来生成界面。
    也可以用其他视图技术,JfreeChart,FreeMarke,JasperReports,JSF,Tiles,Vlocit等。

    如何将网址匹配到Action?框架可能告诉你,在XML文件中配置,且可以分模块配置。
    如何确定该返回那个JSP?框架可能告诉你,在XML文件中配置好了,Action返回SUCCESS,INPUT,LOGIN等等即可。

    Action如何接受参数?框架可能告诉你,写个Setter方法,就可以接受相应参数。不用再从request获取,且类型可自动转换。根据配置处理编码问题。
    Action如何与视图交互?框架可能告诉你,Action自动与视图绑定,在Action写一个Getter方法,试图层就可以用自定义标签获取其值。

    输入校验如何进行?写个validate方法,有错误就调用addActionError方法,自动返回配置中,INPUT指定的页面,页面用<s:actionerrors/>标签就可以自动输出错误信息。
    也可以使用addFieldError方法添加特定field的错误,使用<s:fielderror/>输出特定field的错误信息。
    甚至使用<s:textfield>方法生成的输入框,可以自动显示该字段的错误信息。
     



  • 相关阅读:
    Delphi 正则表达式之TPerlRegEx 类的属性与方法(3): Start、Stop
    Delphi 正则表达式之TPerlRegEx 类的属性与方法(2): 关于子表达式
    Delphi 正则表达式之TPerlRegEx 类的属性与方法(1): 查找
    Delphi 正则表达式语法(10): 选项
    Delphi 正则表达式语法(9): 临界匹配
    Delphi 正则表达式语法(8): 引用子表达式
    Delphi 正则表达式语法(7): 匹配转义字符
    看阿里P7讲MyBatis:从MyBatis的理解以及配置和实现全帮你搞懂
    公司新来的小姐姐不懂java中的static关键字,这样给她描述不香吗?
    2020阿里,字节跳动,JAVA岗(一线企业校招、社招)面试题合集
  • 原文地址:https://www.cnblogs.com/doit8791/p/4211936.html
Copyright © 2011-2022 走看看