• 06Web开发设计模式—MVC&JavaBean


    为了解决web资源开发技术:演变过程
    一、Servlet技术:在Servlet中拼接HTML/JS内容时十分不方便。

    二、JSP:改变了Servlet在Java代码中拼写HTML代码的过程,改变了在HTML中拼写java代码;但是在HTML内容中嵌入大量java代码,仍然会导致java代码和HTML代码混杂在一起,不方便开发维护。

    1. JSP和Servlet
    2. 1、相同点:
    3. JSP看作为一个特殊的Servlet,它只不过是对Servlet的扩展,只要JSP可以完成的工作,使用Servlet都可以完成,
    4. 例如生成动态页面。由于JSP页面最终被转化为Servlet来运行,因此处理请求实际上是编译后的Servlet。
    5. 2、不同点:
    6. (1)、Servlet的实现方式是在JAVA中嵌入HTML代码,编写和修改HTML非常不方便,所以它适合做流程控制、业务处理
    7. 而JSP的实现方式是在HTML中嵌入JAVA代码,比较适合页面的显示。
    8. 例如:在Struts框架中,Servlet位于MVC设计模式的控制层,而JSP位于视图层。
    9. (2)、Servlet没有内置对象,而JSP中的内置对象都是必须通过HttpServletRequest对象、HttpServletResponse
    10. 对象以及HttpServlet对象得到。

    三、JSP+JavaBean:模式一,利用JavaBean将大量代码提取走,JSP负责接受请求、调用程序和展示页面,JavaBean负责封装数据、处理数据。

           过程: 浏览器来访问的时候,请求交给JSP来处理,JSP把其中用户相关的数据封装到JavaBean中,数据封装后,JavaBea提供处理数据的方法,处理好后返回给JSP,JSP拿到处理好的数据展示给用户。
     
    四、Servlet+JSP+JavaBean:模式二,Servlet负责接受请求、控制程序流转,JavaBean负责封装数据、处理数据JSP负责展示页面;
          在这种开发模式下,各个组建都只做自己擅长的事情,从而使程序具有更好的结构性,从而方便开发和维护。                            MVC设计模式
           过程:浏览器来访问的时候,请求交给Servlet来处理,Servlet把其中用户相关的数据封装到JavaBean中,数据封装后,JavaBean提供处理数据的方法,处理好后将数据返回给Servlet;Servlet拿着处理好的数据,通过请求转发的方式,在request域中存好处理的结果,请求转发给JSP;JSP从request域中拿出数据,作为展示页面给浏览器。
           任何软件都可以认为有以下三种模式组成。
           控制器(Control)用来控制程序的流转,界面(View)用来和用户进行交互,模型(Model)用来封装数据和处理业务逻辑的部分。
           一个设计良好的软件,应该将这三个部分尽量的独立开来,互不影响,从而使软件更具有模块化的特点。符合这种思想的软件都称为符合MVC设计模式的软件。
     
    1、控制器C:逻辑处理、控制实体数据在视图上展示、调用模型处理业务请求。
    当 Web 用户单击 Web 页面中的提交按钮来发送 HTML 表单时,控制器接收请求并调用相应的模型组件去处理请求,然后调用相应的视图来显示模型返回的数据。
    2、视图V:数据的展示。
    视图是用户看到并与之交互的界面。视图向用户显示相关的数据,并能接收用户的输入数据,但是它并不进行任何实际的业务处理。视图可以向模型查询业务状态,但不能改变模型。视图还能接受模型发出的数据更新事件,从而对用户界面进行同步更新。
    3、模型M:应用对象。
    模型是应用程序的主体部分。 模型代表了业务数据和业务逻辑; 当数据发生改变时,它要负责通知视图部分;一个模型能为多个视图提供数据。由于同一个模型可以被多个视图重用,所以提高了应用的可重用性。

    五、JavaWeb的经典三层架构
            将模式二中的JavaBean的功能拆分,使JavaBean只负责自己最擅长的工作——封装数据,处理业务逻辑交给service处理数据,访问交给dao,这样以来,每个模块都只做自己擅长的事情,方便程序开发维护。
    1. 一、为什么:要分层
    2. 使软件具有结构性,便于开发、维护和管理。
    3. 将不同功能模块独立,在需要替换某一模块时不需要改动其他模块,方便代码的复用、替换
    4. 二、层与层耦合的概念,利用工厂类解耦
    5. 在分层结构中,我们希望将各个功能
    6. 约束在各自的模块(层)当中的,而当属于某一层的对象、方法“入侵”到了其他层,如将web层的ServletContext对象传入service层,
    7. 或service层调用XMLDao独有的方法,就会导致层与层之间的关系过于“紧密”,当需要修改某一层时不可避免的要修改其他关联的层,
    8. 这和我们软件分层最初的设想-----层与层分离,一个层尽量不依赖其他层存在,当修改一层时无需修改另一层的设想是违背的。
    9. 这种“入侵”造成的“紧密”关系就早做层与层之间发生的“耦合”,而去掉这种耦合性的过程就叫做层与层之间“解耦”
    10. 利用工厂类可以实现解耦的功能
    11. 三、如何判断一项功能到底属于哪一层
    12. 某一项功能属于哪一层,往往是不能明确确定出来的,这时可以参考如下标准进行判断:
    13. 此项功能在业务逻辑上更贴近与哪一层,放在哪一层更能较少耦合
    14. 此项功能是否必须使用某一层特有的对象
    15. 如果放在哪一层都可以,那么放在哪一层更方便技术上的实现,及方便代码的编写和维护
    16. 四、异常的处理
    17. 如果一个异常抛给上一层会增加程序的耦合性,请当场解决:如将xml解析错误抛给service层,那么当换成mysqldao时,
    18. 还需要修改service去掉xml解析异常的处理
    19. 如果上一层明确需要此异常进行代码的流转,请抛出:如当查找一个用户信息而用户找不到时,可以抛出一个用户找不到异常,明确要求上一层处理
    20. 如果这一层和上一层都能解决尽量在这一层解决掉
    21. 如果这一层不能解决,而上一层能解决抛给上一层
    22. 如果所有层都不能解决,则应抛出给虚拟机使线程停止,但是如果直接抛出这个异常,则还需要调用者一级一级继续往上抛出最后才能抛给虚拟机,
    23. 所以还不如在出现异常的位置直接trycatch住后转换为RuntimeException抛出。:如读取配置文件出错,任何层都不能解决,转为RuntimeException抛出,停止线程。
    1、MVC的特点:
        (1)、多个视图可以对应一个模型。减少代码的复制及代码的维护量,一旦模型发生改变,也易于维护。
        (2)、模型返回的数据与显示逻辑分离。模型数据可以应用任何的显示技术,例如,使用JSP页面、Velocity模板或者直接产生Excel文档等。
        (3)、应用被分为三层,降低了各层之间的耦合,提供了应用的可扩展性。
        (4)、控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起,完成不同的请求。因此,控制层可以说是包含了用户请求权限的概念。
        (5)、MVC更适合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,有利于通过工程化和工具化产生管理程序代码。
            遵循MVC模型的JavaWeb的运行流程:
     
     
     六、JavaBean
    (一)、JavaBean简介
            JavaBean是可复用的组件,理论上讲,任何一个Java类都可以是一个Bean。但通常情况下,由于JavaBean是被容器(例如Tomcat)所创建的,因此JavaBean应具有一个无参的构造器,另外,通常JavaBean还要实现Serializable接口用于实现Bean的持久性。JavaBean实际上相当于微软COM模型中的本地进程内COM组件,是不能被跨进程访问的。
         1、JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:
         (1)、这个Java类必须具有一个无参的构造函数
         (2)属性必须私有化
         (3)私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。
         2、虽然Sun公司在定义JavaBean规范时,允许Java开发人员把JavaBean设计得可以像Swing组件一样功能强大,但在实际的J2EE开发中,通常只使用到以上JavaBean最基本的特性。
         3、JavaBean在J2EE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其它程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵守命名规范的方法,从而获知JavaBean的属性,进而调用其属性保存数据。
    (二)、JavaBean的属性
        1、JavaBean的属性可以是任意类型,并且一个JavaBean可以有多个属性。每个属性通常都需要具有相应的setter、 getter方法,setter方法称为属性修改器,getter方法称为属性访问器。
        2、属性修改器必须以小写的set前缀开始,后跟属性名,且属性名的第一个字母要改为大写,例如,name属性的修改器名称为setName,password属性的修改器名称为setPassword。
        3、属性访问器通常以小写的get前缀开始,后跟属性名,且属性名的第一个字母也要改为大写,例如,name属性的访问器名称为getName,password属性的访问器名称为getPassword。
        4、一个JavaBean的某个属性也可以只有set方法或get方法,这样的属性通常也称之为只写、只读属性
    1. import java.io.Serializable;
    2. public class Person implements Serializable{
    3. private String name;
    4. private int age;
    5. public String getName() {
    6. return name;
    7. }
    8. public void setName(String name) {
    9. this.name = name;
    10. }
    11. public int getAge() {
    12. return age;
    13. }
    14. public void setAge(int age) {
    15. this.age = age;
    16. }
    17. }

    (三)、在JSP中使用JavaBean
        1、JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为:
         (1)、<jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
         (2)<jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
         (3)<jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。
        2、<jsp:useBean>标签
         (1)、 用于在指定的域范围内查找指定名称的JavaBean对象:
                1)、如果存在,则直接返回该JavaBean对象的引用。
                2)、如果不存在,则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。
         (2)、常用语法:
    1. <jsp:useBean id="beanName" class="package.class"
    2. scope="page|request|session|application"/>
                1)、id属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称
                2)、class属性用于指定JavaBean的完整类名(即必须带有包名)。
                3)、scope属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application等四个值中的一个,其默认值是page
         (3)、执行原理:

         (4)、带标签体的<jsp:useBean>标签
                1)、语法:
    1. <jsp:useBean ...> 
    2. Body 
    3. </jsp:useBean>

                2)、功能:Body部分的内容只在<jsp:useBean>标签创建JavaBean的实例对象时才执行。
        3、<jsp:setProperty>标签
         (1)、 用于设置和访问JavaBean对象的属性:
         (2)、常用语法:
    1. <jsp:setProperty name="beanName"
    2. {
    3. property="propertyName" value="{string | <%= expression %>}" |
    4. property="propertyName" [ param="parameterName" ] |
    5. property= "*"
    6. }/>
        

                1)、name属性用于指定JavaBean对象的名称。
                2)、property属性用于指定JavaBean实例对象的属性名。
                3)、value属性用于指定JavaBean对象的某个属性的值,value的值可以是字符串,也可以是表达式。为字符串时,该值会自动转化为JavaBean属性相应的类型,如果value的值是一个表达式,那么该表达式的计算结果必须与所要设置的JavaBean属性的类型一致。
                4)、 param属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值,该属性值同样会自动转换成要设置的JavaBean属性的类型。

        4、<jsp:getProperty>标签
         (1)、 用于读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的响应正文中。
         (2)、常用语法:
    1. <jsp:getProperty name="beanInstanceName" property="PropertyName" />

                1)、name属性用于指定JavaBean实例对象的名称,其值应与<jsp:useBean>标签的id属性值相同。
                2)、property属性用于指定JavaBean实例对象的属性名。
         (3)、如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容为“null”的字符串。

    七、JSP开发模式
        1、SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式。
        2、JSP+JavaBean模式适合开发业务逻辑不太复杂的web应用程序,这种模式下,JavaBean用于封装业务数据,JSP即负责处理用户请求,又显示数据。
        3、Servlet+JSP+JavaBean(MVC)模式适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据。 Servlet+JSP、JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式。
    八、案例:
     (一)、使用模式一编写计算器
     
     
     (二)、使用模式二完成用户注册和登陆:
    1、Servlet+jsp+JavaBean+dom4j(XPATH)
    2、JavaEE的经典三层结构
    3、各种功能包
    1. com.lmd.web servlet
    2. com.lmd.service 业务逻辑层
    3. com.lmd.dao
    4. com.lmd.domain JavaBean
    5. com.lmd.util 工具类
    6. com.lmd.test 测试类
    7. com.lmd.exception 异常类
    8. com.lmd.factory() 利用工厂类实现接口
    4、导入第三方包:*junit   dom4j   *JSTL(已内置)  beanutils  
    5、Debug调试模式
    6、配置文件:users.xml(模拟数据库)  config.properties(程序的主配置文件)

            分析从前往后,开发从后往前
    步骤一:导入第三方包到WebRoot--》WEB-INF-》lib下:dom4j-1.6.1.jar和commons-beanutils-1.8.3.jar及其依赖包commons-logging-1.1.1.jar。
    步骤二:在src下新建一个users.xml(模拟数据库)文件和config.properties(工厂类时使用)文件

    步骤三:分析需要开发的内容如上图,接下来开发  分析从前往后,开发从后往前
    1、在com.lmd.domain包下开发JavaBean—User.java:
         记住:Dao中不要混有任何业务逻辑层,只是操作数据库内容。

    2、在com.lmd.dao包下开发XmlUserDao.java:  
          若把Dom4j解析工过程放在此处,每次访问都要解析XML,耗时、浪费时间,并且每个方法中都要解析XML,所以提取出来。因此在中建一个专门解析XML的XmlDaoUtils.java文件,其中:私有构造器的存在可以让某些类不能被实例化和子类化,这些类通常是一些工具类;静态代码块仅在类加载的时候执行一次。
            将共用的功能的放到工具类XmlDaoUtils.java文件中。
    3、 在com.lmd.test包下开发一个测试类XmlUserTest.java文件:
        junit测试包版本不对,会出错。
    4、在com.lmd.service包下开发UserService.java:  (业务逻辑层)

    5、在com.lmd.service包下开发index.jsp等:  (web层:servlet和jsp)
            按照调用顺序开发
        (1)、开发regist.jsp注册界面,里面有验证码;开发验证码ValiImg.java文件,(并在web.xml中配置,Myeclipse不需要)
            开发注册Servlet:RegistServlet.java,其中遇到问题:乱码问题已解决;
            验证码出错后回显注册页面(密码除外),之前填写的注册信息消失,要求回显解决:保存请求参数(param)。
             封装数据的时候,使用user.setUsername(request.getParameter("username"));若多个属性太复杂,可以使用beanutils包下的BeanUtils.populate(userrequest.getParameterMap());
        //TAB 右移   ctrl+TAB 左移  ,在User.java中设一个校验数据的方法。
            注册成功后,回到注册用户的主页。
        (2)、开发注销LogoutServlet.java
        (3)、开发登录界面login.jspLoginServlet.java,并开发记住用户名(存在Cookie中)功能。
           记住用户名:要求再次回到登录页面,记住了用户名(为了不嵌套java代码,使用自定义标签解码用户名的编码,显示出来)
         
    步骤一:导入第三方包到WebRoot--》WEB-INF-》lib下:dom4j-1.6.1.jar和commons-beanutils-1.8.3.jar及其依赖包commons-logging-1.1.1.jar。
    步骤二:在src下新建一个users.xml(模拟数据库)文件和config.properties(工厂类时使用)文件
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <users>
    3. <user username="admin" password="admin" nickname="admin" email="admin8qq.com"/>
    4. </users>

    步骤三:分析需要开发的内容如上图,接下来开发  分析从前往后,开发从后往前
    1、在com.lmd.domain包下开发JavaBean—User.java:
         记住:Dao中不要混有任何业务逻辑层,只是操作数据库内容。
    1. package com.lmd.domain;
    2. import com.lmd.exception.MsgException;
    3. public class User {
    4. private String username;
    5. private String password;
    6. //第二个密码用于验证两个密码是否相等
    7. private String password2;
    8. private String nickname;
    9. private String email;
    10. public String getUsername() {
    11. return username;
    12. }
    13. public void setUsername(String username) {
    14. this.username = username;
    15. }
    16. public String getPassword() {
    17. return password;
    18. }
    19. public void setPassword(String password) {
    20. this.password = password;
    21. }
    22. public String getPassword2() {
    23. return password2;
    24. }
    25. public void setPassword2(String password2) {
    26. this.password2 = password2;
    27. }
    28. public String getNickname() {
    29. return nickname;
    30. }
    31. public void setNickname(String nickname) {
    32. this.nickname = nickname;
    33. }
    34. public String getEmail() {
    35. return email;
    36. }
    37. public void setEmail(String email) {
    38. this.email = email;
    39. }
    40. @Override
    41. public String toString() {
    42. return username + ":" + password;
    43. }
    44. public void checkValue() throws MsgException{
    45. if (username==null || "".equals(username)) {
    46. throw new MsgException("用户名不能为空!");
    47. }
    48. if (password==null || "".equals(password)) {
    49. throw new MsgException("密码不能为空!");
    50. }
    51. if (password2==null || "".equals(password2)) {
    52. throw new MsgException("确认密码不能为空!");
    53. }
    54. if (!password.equals(password2)) {
    55. throw new MsgException("两次密码不一致!");
    56. }
    57. if (nickname==null || "".equals(nickname)) {
    58. throw new MsgException("昵称不能为空!");
    59. }
    60. if (email==null || "".equals(email)) {
    61. throw new MsgException("邮箱不能为空!");
    62. }
    63. //xxxxxx@xxxx.xx
    64. if (!email.matches("^\w+@\w+(\.\w+)$")) {
    65. throw new MsgException("邮箱格式不正确!");
    66. }
    67. }
    68. }
    1. package com.lmd.dao;
    2. import java.util.List;
    3. import org.dom4j.Document;
    4. import org.dom4j.DocumentHelper;
    5. import org.dom4j.Element;
    6. import com.lmd.domain.User;
    7. import com.lmd.util.XmlDaoUtils;
    8. public class XmlUserDao {
    9. /**
    10. * 根据用户名查找用户
    11. * @param username 用户名
    12. * @return 根据用户名找到的用户信息bean,若没找到返回null
    13. */
    14. public User findUserByUserName(String username){
    15. Document dom = XmlDaoUtils.getDom();
    16. Element root = dom.getRootElement();
    17. //在XML中查找具有username属性值等于传入的用户名的元素
    18. List<Element> list = root.selectNodes("//user[@username='"+username+"']");
    19. if (list.size() > 0) {//大于0,找到这个用户
    20. Element userEle = list.get(0);
    21. //将找到的用户信息封装到bean后返回
    22. User user = new User();
    23. user.setUsername(userEle.attributeValue("username"));
    24. user.setPassword(userEle.attributeValue("password"));
    25. user.setNickname(userEle.attributeValue("nickname"));
    26. user.setEmail(userEle.attributeValue("email"));
    27. return user;
    28. }else {//否者找不到
    29. return null;
    30. }
    31. }
    32. /**
    33. * 添加用户
    34. * @param user 要添加的用户信息bean
    35. */
    36. public void addUser(User user){
    37. Document dom = XmlDaoUtils.getDom();
    38. Element root = dom.getRootElement();
    39. //1、凭空创建一个<user>元素,根据传入的user信息,设置此元素的属性
    40. Element userEle = DocumentHelper.createElement("user");
    41. userEle.setAttributeValue("username", user.getUsername());
    42. userEle.setAttributeValue("password", user.getPassword());
    43. userEle.setAttributeValue("nickname", user.getNickname());
    44. userEle.setAttributeValue("email", user.getEmail());
    45. //2、挂载到<user>元素上
    46. root.add(userEle);
    47. //3、回写到XML文件中--共有,提到工具类里
    48. XmlDaoUtils.refXML();
    49. }
    50. /**
    51. * 根据用户名和密码查找对应的用户
    52. * @param username 用户名
    53. * @param password 密码
    54. * @return 找到的用户,若没找到返回null
    55. */
    56. public User findUserByUNandPSW(String username, String password){
    57. Document dom = XmlDaoUtils.getDom();
    58. Element root = dom.getRootElement();
    59. //在XML中查找具有username属性值等于传入的用户名并等于传入密码的元素
    60. List<Element> list = root.selectNodes("//user[@username='"+username+"' and @password='"+password+"']");
    61. if (list.size() > 0) {//大于0,找到这个用户
    62. Element userEle = list.get(0);
    63. //将找到的用户信息封装到bean后返回
    64. User user = new User();
    65. user.setUsername(userEle.attributeValue("username"));
    66. user.setPassword(userEle.attributeValue("password"));
    67. user.setNickname(userEle.attributeValue("nickname"));
    68. user.setEmail(userEle.attributeValue("email"));
    69. return user;
    70. }else {//否者找不到
    71. return null;
    72. }
    73. }
    74. }

    2、在com.lmd.dao包下开发XmlUserDao.java:  
          若把Dom4j解析工过程放在此处,每次访问都要解析XML,耗时、浪费时间,并且每个方法中都要解析XML,所以提取出来。因此在中建一个专门解析XML的XmlDaoUtils.java文件,其中:私有构造器的存在可以让某些类不能被实例化和子类化,这些类通常是一些工具类;静态代码块仅在类加载的时候执行一次。
            将共用的功能的放到工具类XmlDaoUtils.java文件中。
    1. package com.lmd.util;
    2. import java.io.FileOutputStream;
    3. import org.dom4j.Document;
    4. import org.dom4j.io.OutputFormat;
    5. import org.dom4j.io.SAXReader;
    6. import org.dom4j.io.XMLWriter;
    7. /**
    8. * 私有构造器的存在可以让某些类不能被实例化和子类化,
    9. * 这些类通常是一些工具类
    10. * @author angel11288
    11. *
    12. */
    13. public class XmlDaoUtils {
    14. private static Document dom = null;
    15. private static String path = XmlDaoUtils.class.getClassLoader()
    16. .getResource("users.xml").getPath();
    17. //私有构造函数的目的:无法被类以外的函数使用,只能通过调用来实现。
    18. private XmlDaoUtils(){ }
    19. //使XML仅解析一次,要放在静态代码块里
    20. static{
    21. try {
    22. SAXReader reader = new SAXReader();
    23. //类加载器,真实路径要分析,要用相对路径
    24. dom = reader.read(path);
    25. } catch (Exception e) {
    26. e.printStackTrace();
    27. throw new RuntimeException(e);
    28. }
    29. }
    30. public static Document getDom(){
    31. return dom;
    32. }
    33. public static void refXML() {
    34. try {
    35. XMLWriter writer = new XMLWriter(new FileOutputStream(path)
    36. , OutputFormat.createPrettyPrint());
    37. writer.write(dom);
    38. writer.close();
    39. } catch (Exception e) {
    40. e.printStackTrace();
    41. throw new RuntimeException(e);
    42. }
    43. }
    44. }

    3、 在com.lmd.test包下开发一个测试类XmlUserTest.java文件:
        junit测试包版本不对,会出错。
    1. package com.lmd.test;
    2. import org.junit.Test;
    3. import com.lmd.dao.XmlUserDao;
    4. import com.lmd.domain.User;
    5. public class XmlUserTest {
    6. @Test
    7. public void testFindUserByUserName() {
    8. XmlUserDao dao = new XmlUserDao();
    9. User user = dao.findUserByUserName("admin");
    10. System.out.println(user);
    11. //admin:admin
    12. }
    13. @Test
    14. public void testFindUserByUNandPSW() {
    15. XmlUserDao dao = new XmlUserDao();
    16. User user = dao.findUserByUNandPSW("admin", "adminXX");
    17. System.out.println(user);
    18. //admin:admin //null
    19. }
    20. @Test
    21. public void testAddUser() {
    22. XmlUserDao dao = new XmlUserDao();
    23. User user = new User();
    24. user.setUsername("张甜");
    25. user.setPassword("666666");
    26. user.setNickname("小甜甜");
    27. user.setEmail("zhangtian8@163.com");
    28. dao.addUser(user);
    29. //未发布,查看F:webexampleJAVAWEBUserWebRootWEB-INFclasses下users.xml
    30. }
    31. }

    4、在com.lmd.service包下开发UserService.java:  (业务逻辑层)
    1. package com.lmd.service;
    2. import com.lmd.dao.XmlUserDao;
    3. import com.lmd.domain.User;
    4. import com.lmd.exception.MsgException;
    5. /**
    6. * 业务逻辑层
    7. * @author angel11288
    8. */
    9. public class UserService {
    10. private XmlUserDao dao = new XmlUserDao();
    11. /**
    12. * 添加用户
    13. * @param user
    14. * @throws MsgException
    15. */
    16. public void registUser(User user) throws MsgException {
    17. //1、检查用户名是否已经存在,若存在,则提示
    18. if (dao.findUserByUserName(user.getUsername()) != null) {
    19. //此处提示,返回值不太好,返回值被占用;可以使用异常机制提示
    20. throw new MsgException("用户名已经存在");
    21. }
    22. //2、若不存在。则调用dao中的方法添加用户
    23. dao.addUser(user);
    24. }
    25. /**检查用户名和密码是否正确
    26. *
    27. * @param username
    28. * @param password
    29. */
    30. public User isUser(String username, String password) {
    31. return dao.findUserByUNandPSW(username, password);
    32. }
    33. }

    5、在com.lmd.service包下开发index.jsp等:  (web层:servlet和jsp)
    1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    4. <html>
    5. <head>
    6. </head>
    7. <body>
    8. <h1>我的网站</h1> <hr>
    9. <c:if test="${sessionScope.user == null }">
    10. 欢迎光临!游客!
    11. <a href="${pageContext.request.contextPath }/regist.jsp">注册</a>
    12. <a href="${pageContext.request.contextPath }/login.jsp">登录</a>
    13. </c:if>
    14. <c:if test="${sessionScope.user != null }">
    15. 欢迎回来!${sessionScope.user.username }!
    16. <a href="${pageContext.request.contextPath }/LogoutServlet">注销</a>
    17. </c:if>
    18. </body>
    19. </html>

            按照调用顺序开发
        (1)、开发regist.jsp注册界面,里面有验证码;开发验证码ValiImg.java文件,(并在web.xml中配置,Myeclipse不需要)
    1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    4. <html>
    5. <head>
    6. <script type="text/javascript">
    7. function changeImg(img){
    8. //添加后面的时间后,每次点击后,会改变验证码;
    9. //地址不变,加一个时间参数,会刷新
    10. img.src = "/User/ValiImg?time="+new Date().getTime();
    11. }
    12. </script>
    13. </head>
    14. <body style="text-align:center;">
    15. <h1>我的网站_注册</h1> <hr>
    16. <font color="red">${msg}</font>
    17. <form action="${pageContext.request.contextPath }/RegistServlet" method="post">
    18. <table border="1" align="center">
    19. <tr>
    20. <td>用户名</td>
    21. <td><input type="text" name="username" value="${ param.username}" /></td>
    22. </tr>
    23. <!-- requestScope是所有域属性组成的map;而param是请求参数组成的map -->
    24. <tr>
    25. <td>密码</td>
    26. <td><input type="password" name="password" /></td>
    27. </tr>
    28. <tr>
    29. <td>确认密码</td>
    30. <td><input type="password" name="password2" /></td>
    31. </tr>
    32. <tr>
    33. <td>昵称</td>
    34. <td><input type="text" name="nickname" value="${param.nickname }"/></td>
    35. </tr>
    36. <tr>
    37. <td>邮箱</td>
    38. <td><input type="text" name="email" value="${param.email }"/></td>
    39. </tr>
    40. <tr>
    41. <td>验证码</td>
    42. <td><input type="text" name="valistr" /></td>
    43. </tr>
    44. <tr>
    45. <td><input type="submit" value="注册" /></td>
    46. <td><img src="/User/ValiImg" style="cursor:pointer" 
    47. onclick="changeImg(this)"/></td>
    48. </tr>
    49. </table>
    50. </form>
    51. </body>
    52. </html>

            开发注册Servlet:RegistServlet.java,其中遇到问题:乱码问题已解决;
            验证码出错后回显注册页面(密码除外),之前填写的注册信息消失,要求回显解决:保存请求参数(param)。
             封装数据的时候,使用user.setUsername(request.getParameter("username"));若多个属性太复杂,可以使用beanutils包下的BeanUtils.populate(userrequest.getParameterMap());
        //TAB 右移   ctrl+TAB 左移  ,在User.java中设一个校验数据的方法。
            注册成功后,回到注册用户的主页。
    1. package com.lmd.web;
    2. import java.io.IOException;
    3. import java.lang.reflect.InvocationTargetException;
    4. import javax.persistence.metamodel.SetAttribute;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.annotation.WebServlet;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import org.apache.commons.beanutils.BeanUtils;
    11. import com.lmd.domain.User;
    12. import com.lmd.exception.MsgException;
    13. import com.lmd.service.UserService;
    14. /**
    15. * Servlet implementation class RegistServlet
    16. */
    17. @WebServlet("/RegistServlet")
    18. public class RegistServlet extends HttpServlet {
    19. public void doGet(HttpServletRequest request, HttpServletResponse response)
    20. throws ServletException, IOException {
    21. //TAB 右移 ctrl+TAB 左移
    22. try {
    23. request.setCharacterEncoding("UTF-8");
    24. response.setContentType("text/html;charset=UTF-8");
    25. UserService service = new UserService();
    26. //1、检验验证码
    27. String valistr = request.getParameter("valistr");
    28. String valistr2 = (String) request.getSession().getAttribute("valistr");
    29. if (valistr == null || valistr2 == null || !valistr.equals(valistr2)) {
    30. request.setAttribute("msg", "验证码不正确");
    31. request.getRequestDispatcher("/regist.jsp").forward(request, response);;
    32. return;
    33. }
    34. //2、封装数据,校验数据
    35. User user = new User();
    36. BeanUtils.populate(user, request.getParameterMap());
    37. user.checkValue(); //throw new MsgException
    38. //3、调用service中的方法添加用户
    39. service.registUser(user); //throw new MsgException
    40. //4、登录用户
    41. request.getSession().setAttribute("user", user);
    42. //5、提示注册成功回到主页
    43. response.getWriter().write("恭喜您注册成功!3秒后回到主页...");
    44. response.setHeader("Refresh","3;url="+request.getContextPath()+"/index.jsp");
    45. } catch (MsgException me) {
    46. request.setAttribute("msg", me.getMessage());
    47. request.getRequestDispatcher("/regist.jsp").forward(request, response);
    48. } catch (Exception e) {
    49. e.printStackTrace();
    50. throw new RuntimeException(e);
    51. }
    52. }
    53. protected void doPost(HttpServletRequest request, HttpServletResponse response)
    54. throws ServletException, IOException {
    55. doGet(request, response);
    56. }
    57. }

        (2)、开发注销LogoutServlet.java
    1. package com.lmd.web;
    2. import java.io.IOException;
    3. import javax.servlet.ServletException;
    4. import javax.servlet.annotation.WebServlet;
    5. import javax.servlet.http.HttpServlet;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletResponse;
    8. /**
    9. * Servlet implementation class LogoutServlet
    10. */
    11. @WebServlet("/LogoutServlet")
    12. public class LogoutServlet extends HttpServlet {
    13. public void doGet(HttpServletRequest request, HttpServletResponse response)
    14. throws ServletException, IOException {
    15. if (request.getSession(false)!=null && request.getSession()
    16. .getAttribute("user")!=null) {
    17. request.getSession().invalidate();
    18. }
    19. response.sendRedirect(request.getContextPath() + "/index.jsp");
    20. }
    21. protected void doPost(HttpServletRequest request, HttpServletResponse response)
    22. throws ServletException, IOException {
    23. doGet(request, response);
    24. }
    25. }

        (3)、开发登录界面login.jspLoginServlet.java,并开发记住用户名(存在Cookie中)功能。
    1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    3. <%@ taglib uri="http://www.lmd.com/UserTag" prefix="UserTag" %>
    4. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    5. <html>
    6. <head>
    7. </head>
    8. <body>
    9. <div style="text-align: center;">
    10. <h1>我的网站_登录</h1> <hr>
    11. <font color="red">${msg }</font>
    12. <form action="${pageContext.request.contextPath}/LoginServlet" method="post">
    13. <table border="1" align="center">
    14. <tr>
    15. <td>用户名</td>
    16. <td><input type="text" name="username" value="<UserTag:UserTag 
    17. content="${cookie.remname.value }" encode="UTF-8"/>"/></td>
    18. </tr>
    19. <tr>
    20. <td>密码</td>
    21. <td><input type="password" name="password"/></td>
    22. </tr>
    23. <tr>
    24. <td><input type="submit" value="登录"/></td>
    25. <!-- 回显回来,是被勾中的状态 -->
    26. <td><input type="checkbox" value="ok" name="remname"
    27. <c:if test="${cookie.remname != null}">
    28. checked="checked"
    29. </c:if>
    30. />记住用户名</td>
    31. </tr>
    32. </table>
    33. </form>
    34. </div>
    35. </body>
    36. </html>
    1. package com.lmd.web;
    2. import java.io.IOException;
    3. import java.net.URLEncoder;
    4. import javax.servlet.ServletException;
    5. import javax.servlet.annotation.WebServlet;
    6. import javax.servlet.http.Cookie;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import com.lmd.domain.User;
    11. import com.lmd.service.UserService;
    12. /**
    13. * Servlet implementation class LoginServlet
    14. */
    15. @WebServlet("/LoginServlet")
    16. public class LoginServlet extends HttpServlet {
    17. public void doGet(HttpServletRequest request, HttpServletResponse response)
    18. throws ServletException, IOException {
    19. //以后使用过滤器解全栈乱码
    20. request.setCharacterEncoding("UTF-8");
    21. response.setCharacterEncoding("UTF-8");
    22. response.setContentType("text/html;charset=UTF-8");
    23. UserService service = new UserService();
    24. //1、获取客户端提交的用户名和密码
    25. String username = request.getParameter("username");
    26. String password = request.getParameter("password");
    27. //2、调用service中的方法检查用户名和密码
    28. User user = service.isUser(username, password);
    29. if (user == null) {
    30. //3、若不正确,则提示
    31. request.setAttribute("msg", "用户名或密码不正确!");
    32. request.getRequestDispatcher("/login.jsp").forward(request, response);
    33. return;
    34. }else {
    35. //4、正确回到登录主页
    36. request.getSession().setAttribute("user", user);
    37. //实现记住用户名:
    38. if ("ok".equals(request.getParameter("remname"))) {
    39. //若勾住,记住,则发送cookie令浏览器保存用户名
    40. //中文有问题,要编码
    41. Cookie remNameC = new Cookie("remname", 
    42. URLEncoder.encode(user.getUsername()));
    43. remNameC.setPath(request.getContextPath());
    44. remNameC.setMaxAge(3600*30*24);
    45. response.addCookie(remNameC);
    46. }else {
    47. //若不勾住,不记住,则删除记住用户名的cookie
    48. Cookie remNameC = new Cookie("remname", "");
    49. remNameC.setPath(request.getContextPath());
    50. remNameC.setMaxAge(0);
    51. response.addCookie(remNameC);
    52. }
    53. response.sendRedirect(request.getContextPath()+"/index.jsp");
    54. }
    55. }
    56. public void doPost(HttpServletRequest request, HttpServletResponse response)
    57. throws ServletException, IOException {
    58. doGet(request, response);
    59. }
    60. }

           记住用户名:要求再次回到登录页面,记住了用户名(为了不嵌套java代码,使用自定义标签解码用户名的编码,显示出来)
     
    1. package com.lm.tag;
    2. import java.io.IOException;
    3. import java.net.URLDecoder;
    4. import javax.servlet.jsp.JspException;
    5. import javax.servlet.jsp.tagext.SimpleTagSupport;
    6. public class URLEncoderTag extends SimpleTagSupport{
    7. private String content;
    8. private String encode;
    9. public void setContent(String content) {
    10. this.content = content;
    11. }
    12. public void setEncode(String encode) {
    13. this.encode = encode;
    14. }
    15. @Override
    16. public void doTag() throws JspException, IOException {
    17. //encode设置<required>false</required>,非必须
    18. String s = URLDecoder.decode(content, encode == null ? "UTF-8" : encode);
    19. getJspContext().getOut().write(s);
    20. }
    21. }

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    4. xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    5. http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
    6. <tlib-version>1.0</tlib-version>
    7. <short-name>UserTag</short-name>
    8. <uri>http://www.lmd.com/UserTag</uri>
    9. <tag>
    10. <name>UserTag</name>
    11. <tag-class>com.lm.tag.URLEncoderTag</tag-class>
    12. <body-content>empty</body-content>
    13. <attribute>
    14. <name>content</name>
    15. <required>true</required>
    16. <rtexprvalue>true</rtexprvalue>
    17. <type>java.lang.String</type>
    18. </attribute>
    19. <attribute>
    20. <name>encode</name>
    21. <required>false</required>
    22. <rtexprvalue>true</rtexprvalue>
    23. <type>java.lang.String</type>
    24. </attribute>
    25. </tag>
    26. </taglib>
     
     
     
     
     
     

     


     
  • 相关阅读:
    点击按钮在表格的某一行下,在添加一行(HTML+JS)
    13
    12 stark组件之pop,按钮,url,页面
    11 stark组件之delete按钮、filter过滤
    解决 AttributeError: 'ForeignKey' object has no attribute 're'
    360面经
    4 django篇
    0- 26个面试经典问题回答
    如何学习??
    LeetCode
  • 原文地址:https://www.cnblogs.com/angel11288/p/dda1d00a38723b0415d45c6b8352ec08.html
Copyright © 2020-2023  润新知