Web开发模式

Posted yolo929

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web开发模式相关的知识,希望对你有一定的参考价值。

原文链接

开发模式的介绍(完善版)

在Web开发模式中,有两个主要的开发结构,称为模式一(Mode I)和模式二(Mode II).

首先我们来理清一些概念吧:

  • DAO(Data Access Object):主要对数据的操作,增加、修改、删除等原子性操作。

  • Web层:界面+控制器,也就是说JSP【界面】+Servlet【控制器】

  • Service业务层:将多个原子性的DAO操作进行组合,组合成一个完整的业务逻辑

  • 控制层:主要使用Servlet进行控制

  • 数据访问层:使用DAO、Hibernate、JDBC技术实现对数据的增删改查

  • JavaBean用于封装数据,处理部分核心逻辑,每一层中都用到!

模式一

模式一指的就是在开发中将显示层、控制层、数据层的操作统一交给JSP或者JavaBean来进行处理

模式一有两种情况:

  • 完全使用JSP做开发

  • 优点:

    1. 开发速度贼快,只要写JSP就行了,JavaBean和Servlet都不用设计!

    2. 小幅度修改代码方便,直接修改JSP页面交给WEB容器就行了,不像Servlet还要编译成.class文件再交给服务器!【当然了,在ide下开发这个也不算是事】

  • 缺点:

    1. 程序的可读性差、复用性低、代码复杂!什么jsp代码、html代码都往上面写,这肯定很难阅读,很难重用!

  • 使用JSP+JavaBean做开发

  • 优点:

    1. 程序的可读性较高,大部分的代码都写在JavaBean上,不会和HTML代码混合在一起,可读性还行的。

    2. 可重复利用高,核心的代码都由JavaBean开发了,JavaBean的设计就是用来重用、封装,大大减少编写重复代码的工作!

  • 缺点:

    1. 没有流程控制,程序中的JSP页面都需要检查请求的参数是否正确,异常发生时的处理。显示操作和业务逻辑代码工作会紧密耦合在一起的!日后维护会困难

应用例子:

我们使用JavaBean+JSP开发一个简易的计算器吧,效果如图下:

技术图片

  • 首先开发JavaBean对象

public class Calculator {

  private double firstNum;
  private double secondNum;
  private char Operator = ‘+‘;
  private double result;


  //JavaBean提供了计算的功能
  public void calculate() {

    switch (this.Operator) {
      case ‘+‘:
        this.result = this.firstNum + this.secondNum;
        break;

      case ‘-‘:
        this.result = this.firstNum - this.secondNum;
        break;

      case ‘*‘:
        this.result = this.firstNum * this.secondNum;
        break;

      case ‘/‘:
        if (this.secondNum == 0) {
          throw new RuntimeException("除数不能为0");
        }
        this.result = this.firstNum / this.secondNum;
        break;

      default:
        throw new RuntimeException("传入的字符非法!");
    }
  }


  public double getFirstNum() {
    return firstNum;
  }

  public void setFirstNum(double firstNum) {
    this.firstNum = firstNum;
  }

  public double getSecondNum() {
    return secondNum;
  }

  public void setSecondNum(double secondNum) {
    this.secondNum = secondNum;
  }

  public char getOperator() {
    return Operator;
  }

  public void setOperator(char operator) {
    Operator = operator;
  }

  public double getResult() {
    return result;
  }

  public void setResult(double result) {
    this.result = result;
  }
}
  • 再开发显示页面

<%--开发用户界面--%>
  <form action="/zhongfucheng/1.jsp" method="post">
    <table border="1">
      <tr>
        <td colspan="2">简单计数器</td>
        <td></td>
      </tr>
      <tr>
        <td>第一个参数:</td>
        <td><input type="text" name="firstNum"></td>
      </tr>
      <tr>
        <td>运算符</td>
        <td>
          <select name="operator">
            <option value="+">+</option>
            <option value="-">-</option>
            <option value="*">*</option>
            <option value="/">/</option>
          </select>
        </td>
      </tr>
      <tr>
        <td>第二个参数:</td>
        <td><input type="text " name="secondNum"></td>
      </tr>
      <tr>
        <td colspan="2"><input type="submit" value="提交"></td>
        <td></td>
      </tr>
    </table>
  </form>
  • 导jstl和standard包

      技术图片

  • 获取得到显示页面提交的参数,调用JavaBean的方法,最后输出结果!
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--获取得到Bean对象--上面是jstl标签库声明%>
  <jsp:useBean id="calculator" class="model.Calculator" scope="page"/>

  <%--设置Bean对象的数据--%>
  <jsp:setProperty name="calculator" property="*"/>

  <%--调用Caculator的方法计算出值--%>
  <%
      calculator.calculate();
  %>
  <%--得出的结果:--%>
  <c:out value="计算得出的结果是:"/>
  <jsp:getProperty name="calculator" property="firstNum"/>
  <jsp:getProperty name="calculator" property="operator"/>
  <jsp:getProperty name="calculator" property="secondNum"/>
  <c:out value="="/>
  <jsp:getProperty name="calculator" property="result"/>

 

模式二

Mode II 中所有的开发都是以Servlet为主体展开的,由Servlet接收所有的客户端请求,然后根据请求调用相对应的JavaBean,并所有的显示结果交给JSP完成!,也就是俗称的MVC设计模式!

MVC设计模式:

  • 模型层(Mode):模型层包括了业务层,DAO层。
  • 显示层(View):主要负责接受Servlet传递的内容,调用JavaBean,将内容显示给用户

  • 控制层(Controller):主要负责所有用户的请求参数,判断请求参数是否合法,根据请求的类型调用JavaBean,将最终的处理结果交给显示层显示!

应用例子:

我们使用MVC模式开发一个简单的用户登陆注册的案例吧!作为一个简单的用户登陆注册,这里就直接使用XML文档当作小型数据库吧

①搭建开发环境

  • 导入相对应的开发包

    • 这里为了导包方便,用Maven管理。(可点击查看)
    •  <dependencies>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.12</version>
                  <scope>test</scope>
              </dependency>
      
              <dependency>
                  <groupId>javax.servlet</groupId>
                  <artifactId>servlet-api</artifactId>
                  <version>2.5</version>
              </dependency>
      
              <dependency>
                  <groupId>javax.servlet.jsp</groupId>
                  <artifactId>jsp-api</artifactId>
                  <version>2.1</version>
                  <scope>provided</scope>
              </dependency>
      
              <dependency>
                  <groupId>jstl</groupId>
                  <artifactId>jstl</artifactId>
                  <version>1.2</version>
              </dependency>
      
              <dependency>
                  <groupId>dom4j</groupId>
                  <artifactId>dom4j</artifactId>
                  <version>1.6.1</version>
              </dependency>
      
              <dependency>
                  <groupId>jaxen</groupId>
                  <artifactId>jaxen</artifactId>
                  <version>1.1.6</version>
              </dependency>
      
              <dependency>
                  <groupId>commons-beanutils</groupId>
                  <artifactId>commons-beanutils</artifactId>
                  <version>1.9.3</version>
              </dependency>
      
          </dependencies>
  • 创建程序的包名

技术图片

  • 创建xml文件,当做小型的数据库(解析需要用dom4j包和jaxen包)

<?xml version="1.0" encoding="UTF-8"?>

<users>
    <user id="1" username="yolo" password="123" email="[email protected]" birthday="2000-09-09"/>
</users>

②开发实体User

    private int id;
    private String username;
    private String password;
    private String email;
    private Date birthday;
//各种Setter,Getter
//无参构造和带参构造

③开发dao

  • 注册(外界传递一个User对象进来,我可以在XML文档多一条信息)。
  • 登陆(外界传递用户名和密码过来,我就在XML文档中查找有没该用户名和密码,如果有就返回一个User对象)
  • 3.1登陆功能

  • 解析Xml的UserImplXML类

 //外界传递用户名和密码进来,我要在XML文档中查找是否有该条记录
    public User find(String username, String password) {
        //得到XML文档的流对象
        InputStream inputStream = UserImplXML.class.getClassLoader().getResourceAsStream("user.xml");
        //得到dom4j的解析器对象
        SAXReader saxReader = new SAXReader();
        try {
            //解析XML文档
            Document document = saxReader.read(inputStream);

            //使用XPATH技术,查找XML文档中是否有传递进来的username和password
            Element element = (Element) document.selectSingleNode("//user[@username=‘" + username + "‘ [email protected]=‘" + password + "‘]");

            if (element == null) {
                return null;
            }

            //如果有,就把XML查出来的节点信息封装到User对象,返回出去
            User user = new User();
            user.setId(Integer.parseInt(element.attributeValue("id")));
            user.setUsername(element.attributeValue("username"));
            user.setPassword(element.attributeValue("password"));
            user.setEmail(element.attributeValue("email"));

            //生日就需要转换一下了,XML文档保存的是字符串,User对象需要的是Date类型
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd");
            Date birthday = simpleDateFormat.parse(element.attributeValue("birthday"));
            user.setBirthday(birthday);

            //返回User对象出去
            return user;

        } catch (DocumentException e) {
            e.printStackTrace();
            throw new RuntimeException("初始化时候出错啦!");
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException("查询的时候出错啦!");
        }
  }
  • 将其抽取为接口UserDao,在test文件夹下测试一下(需要导入JUnit包
 @Test
    public void testLogin() {

        UserDao userImplXML = new UserImplXML();
        User user = userImplXML.find(username, password);

        System.out.println(user.getBirthday());
        System.out.println(user.getEmail());
        System.out.println(user.getId());
        System.out.println(user.getUsername());
        System.out.println(user.getPassword());

    }

  3.2注册功能

 //注册功能,外界传递一个User对象进来。我就在XML文档中添加一条信息
    public void register(User user) {
        //获取XML文档路径!
        String path = UserImplXML.class.getClassLoader().getResource("user.xml").getPath();

        try {
            //获取dom4j的解析器,解析XML文档
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(path);

            //在XML文档中创建新的节点
            Element newElement = DocumentHelper.createElement("user");
            newElement.addAttribute("id", String.valueOf(user.getId()));
            newElement.addAttribute("username", user.getUsername());
            newElement.addAttribute("email", user.getEmail());
            newElement.addAttribute("password", user.getPassword());

            //日期返回的是指定格式的日期
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd");
            String date = simpleDateFormat.format(user.getBirthday());
            newElement.addAttribute("birthday",date);

            //把新创建的节点增加到父节点上
            document.getRootElement().add(newElement);

            //把XML内容中文档的内容写到硬盘文件上
            OutputFormat outputFormat = OutputFormat.createPrettyPrint();
            outputFormat.setEncoding("UTF-8");
            XMLWriter xmlWriter = new XMLWriter(new FileWriter(path),outputFormat);
            xmlWriter.write(document);
            xmlWriter.close();

        } catch (DocumentException e) {
            e.printStackTrace();
            throw new RuntimeException("注册的时候出错了!!!");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("注册的时候出错了!!!");
        }
    }

同样测试一下

 @Test
    public void testRegister() {

        UserDao userImplXML = new UserImplXML();

        //这里我为了测试的方便,就添加一个带5个参数的构造函数了!
        User user = new User(10, "yoyoyo", "123", "[email protected]", new Date());

        userImplXML.register(user);
    }
}

注意:测试的结果是在target文件夹的classes目录下的user.xml文件查询的。

④开发service层

public class UserServiceXML{

    //Service层就是调用Dao层的方法,我们就直接在类中创建Dao层的对象了
    private UserDao userImplXML = new UserImplXML();

    public void register(User user) {
        userImplXML.register(user);
    }
  public User login(String username, String password) {
      return userImplXML.find(username, password);
  }
 }

为了更好的解耦,也把它抽取成接口ServiceBussiness。

⑤开发web层

5.1注册界面

  • 提供注册界面的Servlet
@WebServlet(name = "RegisterUIServlet")
public class RegisterUIServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("register.jsp").forward(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  • 开发注册界面的JSP
<h1>欢迎来到注册界面!</h1>

<%--提交给处理注册的处理Servlet--%>
<form method="post" action="${pageContext.request.contextPath}/RegisterServlet">

    <table>
        <%--对于id来讲,是服务器分配的!不需要用户自己输入--%>
        <tr>
            <td>用户名</td>
            <td>
                <input type="text " name="username">
            </td>
        </tr>
        <tr>
            <td>密码</td>
            <td>
                <input type="text" name="password">
            </td>
        </tr>
        <tr>
            <td>确认密码</td>
            <td>
                <input type="text" name="password">
            </td>
        </tr>
        <tr>
            <td>邮箱</td>
            <td>
                <input type="text" name="email">
            </td>
        </tr>
        <tr>
            <td>生日</td>
            <td>
                <input type="text " name="birthday">
            </td>
        </tr>
        <tr>
            <td>
                <input type="submit" value="提交">
            </td>
            <td>
                <input type="reset" value="重置!">
            </td>
        </tr>
    </table>
</form>
  • 我们要开发处理用户注册提交的Servlet(用到beanutils包)
//首先要接受Parameter的参数,封装到User里面去
String username = request.getParameter("username");
String password = request.getParameter("password");

//......如果参数过多,我们就要写好多好多类似的代码了...
  • 所以需要开发一个工具类WebUtils,用反射机制中的BeanUtils开发包
 public static int makeId() {
        BigInteger bigInteger=new BigInteger(UUID.randomUUID().toString().replace("-",""),16);
        return bigInteger.intValue();
    }
    public static <T> T request2Bean(HttpServletRequest httpServletRequest, Class<T> tClass) {

        try {
            //创建tClass的对象
            T bean = tClass.newInstance();

            //获取得到Parameter中全部的参数的名字
            Enumeration enumeration = httpServletRequest.getParameterNames();
           //监测setProperty,将String转为Date
           ConvertUtils.register(new DateLocaleConverter(), Date.class);
            //遍历上边获取得到的集合
            while (enumeration.hasMoreElements()) {

                //获取得到每一个带过来参数的名字
                String name = (String) enumeration.nextElement();

                //获取得到值
                String value = httpServletRequest.getParameter(name);

                //把数据封装到Bean对象中
                BeanUtils.setProperty(bean, name, value);

            }
            return bean;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("封装数据到Bean对象中出错了!");
        }
    }        
  • 原本makeId()用的是
public static int makeId() {
  return Integer.parseInt(UUID.randomUUID().toString());
}
//抛出异常,因为String由parseInt转换后的数值超过int的范围
  •  我们来测试一下吧!以下是RegisterServlet的代码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        User user = WebUtils.request2Bean(request, User.class);
        user.setId(WebUtils.makeId());

        //调用service层的注册方法,实现注册
        ServiceBussiness serviceBussiness = new UserServiceXML();
        serviceBussiness.register(user);
    }

注意:测试的结果是在target文件夹下的

技术图片

  • 校验用户输入的信息,如果用户输入的信息不合法,就直接跳转回注册的界面
    • 刚才我们是用BeanUtils把Parameter的信息全部直接封装到User对象中,但现在我想要验证用户提交表单的数据,也应该把表单的数据用一个对象保存着【面向对象的思想、封装、重用】

    • 流程是这样子的:当用户提交表单数据的时候,就把表单数据封装到我们设计的表单对象上,调用表单对象的方法,验证数据是否合法!

public class FormBean {

    //表单提交过来的数据全都是String类型的,birthday也不例外!
    private String username;
    private String password;
    private String password2;
    private String email;
    private String birthday;

    //记录错误的信息
    private HashMap<String, String> error = new HashMap<String, String>();

    /*用于判断表单提交过来的数据是否合法*/
    public boolean validate() {

        //用户名不能为空,并且要是3-8的字符 abcdABcd
        if (this.username == null || this.username.trim().equals("")) {

            error.put("username", "用户名不能为空,并且要是3-8的字符");
            return false;

        } else {
            if (!this.username.matches("[a-zA-Z]{3,8}")) {
                error.put("username", "用户名不能为空,并且要是3-8的字符");
                return false;
            }
        }

        //密码不能为空,并且要是3-8的数字
        if (this.password == null || this.password.trim().equals("")) {
            error.put("password", "密码不能为空,并且要是3-8的数字");
            return false;
        } else {
            if (!this.password.matches("\\\\d{3,8}")) {
                error.put("password", "密码不能为空,并且要是3-8的数字");
                return false;
            }
        }

        //两次密码要一致
        if (this.password2 != null && !this.password2.trim().equals("")) {
            if (!this.password2.equals(this.password)) {
                error.put("password2", "两次密码要一致");
                return false;
            }
        }

        //邮箱可以为空,如果为空就必须合法
        if (this.email != null && !this.email.trim().equals("")) {
            if (!this.email.matches("\\\\[email protected]\\\\w+(\\\\.\\\\w+)+")) {

                error.put("email", "邮箱不合法!");
                return false;
            }
        }

        //日期可以为空,如果为空就必须合法
        if (this.birthday != null && !this.birthday.trim().equals("")) {

            try {
                DateLocaleConverter dateLocaleConverter = new DateLocaleConverter();
                dateLocaleConverter.convert(this.birthday);
            } catch (Exception e) {

                error.put("birthday", "日期不合法!");
                return false;
            }
        }

        //如果上面都没有执行,那么就是合法的了,返回true
        return true;
    }
//各种Setter,Getter
}

修改处理表单数据的Servlet

     //将表单的数据封装到formBean中
        FormBean formBean = WebUtils.request2Bean(request, FormBean.class);

        //验证表单的数据是否合法,如果不合法就跳转回去注册的页面
        if(formBean.validate()==false){
            //在跳转之前,把formbean对象传递给注册页面
            request.setAttribute("formbean", formBean);
            request.getRequestDispatcher("register.jsp").forward(request, response);
            return;
        }
        try {

            //这是第一种,合法后直接读取
           /*User user = WebUtils.request2Bean(request,User.class);
            user.setId(WebUtils.makeId());*/
            //-----------------------------------

            //这是第二种,从formBean那里拷贝
            User user = new User();
            user.setId(WebUtils.makeId());
            BeanUtils.copyProperties(user,formBean);
            //------------------------------------------

            //调用service层的注册方法,实现注册
            ServiceBussiness serviceBussiness = new UserServiceXML();
            serviceBussiness.register(user);

        } catch (Exception e) {
            e.printStackTrace();
        }

将数据封装到User对象中的第二种方法

  • 我们知道BeanUtils有个copyProperties()方法,可以将某个对象的成员数据拷贝到另外一个对象的成员变量数据上(前提是成员变量的名称相同!)我们FormBean对象的成员变量名称和User对象的成员变量的名称是一致的!并且,前面在验证的时候,我们已经把Parameter中带过来的数据封装到了FormBean对象中了,所以我们可以使用copyProperties()方法!

  • 使用该方法时,值得注意的是:第一个参数是拷贝到哪一个对象上(也就是User对象),第二个参数是被拷贝的对象(也就是formbean对象),口诀:后拷前….不要搞混了

技术图片

现在测试下,如果没有输入日期呢?

  • 表单数据提交给Servlet,Servlet将表单的数据(Parameter中的数据)用BeanUtils封装到User对象中,当封装到日期的时候,发现日期为null,无法转换成日期对象,抛出异常!

那我们现在要怎么解决呢?

  • 因为我们在设定的时候,已经允许了email和birthday可以为空,那么在DAO层就应该有相应的逻辑判断email和birthday是否为空!
         if (user.getEmail() == null) {
                newElement.addAttribute("email", "");
            } else {
                newElement.addAttribute("email", user.getEmail());
            }

            //如果不是空才格式化信息
            if (user.getBirthday() == null) {
                newElement.addAttribute("birthday", "");
            } else {
                //日期返回的是指定格式的日期
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                String date = simpleDateFormat.format(user.getBirthday());
                newElement.addAttribute("birthday", date);
            }            

 当发现用户输入的信息不合法时,把错误的信息记录下来,等到返回注册页面,就提示用户哪里出错了!

  • 修改注册页面register.jsp中,使用EL表达式把错误的信息写出来,并将数据回显
<table>
        <%--对于id来讲,是服务器分配的!不需要用户自己输入--%>
        <tr>
            <td>用户名</td>
            <td>
                <input type="text" name="username" value="${formbean.username}">${formbean.errors.username}
            </td>
        </tr>
        <tr>
            <td>密码</td>
            <td>
                <input type="text" name="password" value="${formbean.password}">${formbean.errors.password}
            </td>
        </tr>
        <tr>
            <td>确认密码</td>
            <td>
                <input type="text" name="password2" value="${formbean.password2}">${formbean.errors.password2}
            </td>
        </tr>
       //......

5.2登录界面

  • 首先写一个提供登陆界面的LoginUIServlet
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //直接跳转到登陆界面
        request.getRequestDispatcher("login.jsp").forward(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
  • 写登陆界面login.jsp
<h1>这是登陆界面</h1>

<form action="${pageContext.request.contextPath}/LoginServlet" method="post">
    <table>
        <tr>
            <td>用户名</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
            <td><input type="reset" name="重置"></td>
        </tr>
    </table>
</form>
  • 写处理登陆表单的LoginServlet
//获取提交过来的数据
String username = request.getParameter("username");
String password = request.getParameter("password");

//调用service层的方法,去查询数据库(XML)是否有该条记录
try {
  ServiceBussiness serviceBussiness = new UserServiceXML();
  User user = serviceBussiness.login(username, password);

  if (user == null) {
    request.setAttribute("message", "用户名或密码是错的");
  } else {
    request.setAttribute("message","登陆成功");
  }
} catch (Exception e) {
  e.printStackTrace();
  request.setAttribute("message","登陆失败咯");
}
request.getRequestDispatcher("/message.jsp").forward(request, response);
  • 设置首页home.jsp(在web.xml中配置welcome-file)
<h1>这是首页!</h1>
<a href="${pageContext.request.contextPath}/LoginUIServlet">登陆</a>
<a href="${pageContext.request.contextPath}/RegisterUIServlet">注册</a>

以上是关于Web开发模式的主要内容,如果未能解决你的问题,请参考以下文章

几条jQuery代码片段助力Web开发效率提升

web前端开发JQuery常用实例代码片段(50个)

十条jQuery代码片段助力Web开发效率提升

十条jQuery代码片段助力Web开发效率提升

markdown Snippets.md是我最常用的HTML,CSS和JavaScript代码片段,用于前端Web开发

PHP必用代码片段