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:\webexample\JAVAWEB\User\WebRoot\WEB-INF\classes下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>
 
 
 
 
 
 

 


 
posted @ 2017-02-28 11:06  欧阳蝶梦  阅读(257)  评论(0编辑  收藏  举报