06Web开发设计模式—MVC&JavaBean
为了解决web资源开发技术:演变过程
![]()
![]()
//TAB 右移 ctrl+TAB 左移 ,在User.java中设一个校验数据的方法。
![]()
![]()
![]()
![]()
一、Servlet技术:在Servlet中拼接HTML/JS内容时十分不方便。
二、JSP:改变了Servlet在Java代码中拼写HTML代码的过程,改变了在HTML中拼写java代码;但是在HTML内容中嵌入大量java代码,仍然会导致java代码和HTML代码混杂在一起,不方便开发维护。
JSP和Servlet1、相同点:JSP看作为一个特殊的Servlet,它只不过是对Servlet的扩展,只要JSP可以完成的工作,使用Servlet都可以完成,例如生成动态页面。由于JSP页面最终被转化为Servlet来运行,因此处理请求实际上是编译后的Servlet。2、不同点:(1)、Servlet的实现方式是在JAVA中嵌入HTML代码,编写和修改HTML非常不方便,所以它适合做流程控制、业务处理;而JSP的实现方式是在HTML中嵌入JAVA代码,比较适合页面的显示。例如:在Struts框架中,Servlet位于MVC设计模式的控制层,而JSP位于视图层。(2)、Servlet没有内置对象,而JSP中的内置对象都是必须通过HttpServletRequest对象、HttpServletResponse对象以及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,这样以来,每个模块都只做自己擅长的事情,方便程序开发维护。
一、为什么:要分层使软件具有结构性,便于开发、维护和管理。将不同功能模块独立,在需要替换某一模块时不需要改动其他模块,方便代码的复用、替换二、层与层耦合的概念,利用工厂类解耦在分层结构中,我们希望将各个功能约束在各自的模块(层)当中的,而当属于某一层的对象、方法“入侵”到了其他层,如将web层的ServletContext对象传入service层,或service层调用XMLDao独有的方法,就会导致层与层之间的关系过于“紧密”,当需要修改某一层时不可避免的要修改其他关联的层,这和我们软件分层最初的设想-----层与层分离,一个层尽量不依赖其他层存在,当修改一层时无需修改另一层的设想是违背的。这种“入侵”造成的“紧密”关系就早做层与层之间发生的“耦合”,而去掉这种耦合性的过程就叫做层与层之间“解耦”利用工厂类可以实现解耦的功能三、如何判断一项功能到底属于哪一层某一项功能属于哪一层,往往是不能明确确定出来的,这时可以参考如下标准进行判断:此项功能在业务逻辑上更贴近与哪一层,放在哪一层更能较少耦合此项功能是否必须使用某一层特有的对象如果放在哪一层都可以,那么放在哪一层更方便技术上的实现,及方便代码的编写和维护四、异常的处理如果一个异常抛给上一层会增加程序的耦合性,请当场解决:如将xml解析错误抛给service层,那么当换成mysqldao时,还需要修改service去掉xml解析异常的处理如果上一层明确需要此异常进行代码的流转,请抛出:如当查找一个用户信息而用户找不到时,可以抛出一个用户找不到异常,明确要求上一层处理如果这一层和上一层都能解决尽量在这一层解决掉如果这一层不能解决,而上一层能解决抛给上一层如果所有层都不能解决,则应抛出给虚拟机使线程停止,但是如果直接抛出这个异常,则还需要调用者一级一级继续往上抛出最后才能抛给虚拟机,所以还不如在出现异常的位置直接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方法,这样的属性通常也称之为只写、只读属性。
import java.io.Serializable;public class Person implements Serializable{private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
(三)、在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)、常用语法:
<jsp:useBean id="beanName" class="package.class"scope="page|request|session|application"/>
1)、id属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
2)、class属性用于指定JavaBean的完整类名(即必须带有包名)。
3)、scope属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application等四个值中的一个,其默认值是page。
(3)、执行原理:
(4)、带标签体的<jsp:useBean>标签
1)、语法:
<jsp:useBean ...>Body</jsp:useBean>
2)、功能:Body部分的内容只在<jsp:useBean>标签创建JavaBean的实例对象时才执行。
3、<jsp:setProperty>标签
(1)、 用于设置和访问JavaBean对象的属性:
(2)、常用语法:
<jsp:setProperty name="beanName"{property="propertyName" value="{string | <%= expression %>}" |property="propertyName" [ param="parameterName" ] |property= "*"}/>
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)、常用语法:
<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、各种功能包
com.lmd.web servletcom.lmd.service 业务逻辑层com.lmd.daocom.lmd.domain JavaBeancom.lmd.util 工具类com.lmd.test 测试类com.lmd.exception 异常类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(user, request.getParameterMap());
注册成功后,回到注册用户的主页。
(2)、开发注销LogoutServlet.java
(3)、开发登录界面login.jsp和LoginServlet.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(工厂类时使用)文件:
<?xml version="1.0" encoding="UTF-8"?><users><user username="admin" password="admin" nickname="admin" email="admin8qq.com"/></users>
步骤三:分析需要开发的内容如上图,接下来开发 分析从前往后,开发从后往前
1、在com.lmd.domain包下开发JavaBean—User.java:
记住:Dao中不要混有任何业务逻辑层,只是操作数据库内容。
package com.lmd.domain;import com.lmd.exception.MsgException;public class User {private String username;private String password;//第二个密码用于验证两个密码是否相等private String password2;private String nickname;private String email;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getPassword2() {return password2;}public void setPassword2(String password2) {this.password2 = password2;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Overridepublic String toString() {return username + ":" + password;}public void checkValue() throws MsgException{if (username==null || "".equals(username)) {throw new MsgException("用户名不能为空!");}if (password==null || "".equals(password)) {throw new MsgException("密码不能为空!");}if (password2==null || "".equals(password2)) {throw new MsgException("确认密码不能为空!");}if (!password.equals(password2)) {throw new MsgException("两次密码不一致!");}if (nickname==null || "".equals(nickname)) {throw new MsgException("昵称不能为空!");}if (email==null || "".equals(email)) {throw new MsgException("邮箱不能为空!");}//xxxxxx@xxxx.xxif (!email.matches("^\\w+@\\w+(\\.\\w+)$")) {throw new MsgException("邮箱格式不正确!");}}}
package com.lmd.dao;import java.util.List;import org.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import com.lmd.domain.User;import com.lmd.util.XmlDaoUtils;public class XmlUserDao {/*** 根据用户名查找用户* @param username 用户名* @return 根据用户名找到的用户信息bean,若没找到返回null*/public User findUserByUserName(String username){Document dom = XmlDaoUtils.getDom();Element root = dom.getRootElement();//在XML中查找具有username属性值等于传入的用户名的元素List<Element> list = root.selectNodes("//user[@username='"+username+"']");if (list.size() > 0) {//大于0,找到这个用户Element userEle = list.get(0);//将找到的用户信息封装到bean后返回User user = new User();user.setUsername(userEle.attributeValue("username"));user.setPassword(userEle.attributeValue("password"));user.setNickname(userEle.attributeValue("nickname"));user.setEmail(userEle.attributeValue("email"));return user;}else {//否者找不到return null;}}/*** 添加用户* @param user 要添加的用户信息bean*/public void addUser(User user){Document dom = XmlDaoUtils.getDom();Element root = dom.getRootElement();//1、凭空创建一个<user>元素,根据传入的user信息,设置此元素的属性Element userEle = DocumentHelper.createElement("user");userEle.setAttributeValue("username", user.getUsername());userEle.setAttributeValue("password", user.getPassword());userEle.setAttributeValue("nickname", user.getNickname());userEle.setAttributeValue("email", user.getEmail());//2、挂载到<user>元素上root.add(userEle);//3、回写到XML文件中--共有,提到工具类里XmlDaoUtils.refXML();}/*** 根据用户名和密码查找对应的用户* @param username 用户名* @param password 密码* @return 找到的用户,若没找到返回null*/public User findUserByUNandPSW(String username, String password){Document dom = XmlDaoUtils.getDom();Element root = dom.getRootElement();//在XML中查找具有username属性值等于传入的用户名并等于传入密码的元素List<Element> list = root.selectNodes("//user[@username='"+username+"' and @password='"+password+"']");if (list.size() > 0) {//大于0,找到这个用户Element userEle = list.get(0);//将找到的用户信息封装到bean后返回User user = new User();user.setUsername(userEle.attributeValue("username"));user.setPassword(userEle.attributeValue("password"));user.setNickname(userEle.attributeValue("nickname"));user.setEmail(userEle.attributeValue("email"));return user;}else {//否者找不到return null;}}}
2、在com.lmd.dao包下开发XmlUserDao.java:
若把Dom4j解析工过程放在此处,每次访问都要解析XML,耗时、浪费时间,并且每个方法中都要解析XML,所以提取出来。因此在中建一个专门解析XML的XmlDaoUtils.java文件,其中:私有构造器的存在可以让某些类不能被实例化和子类化,这些类通常是一些工具类;静态代码块仅在类加载的时候执行一次。
将共用的功能的放到工具类XmlDaoUtils.java文件中。
package com.lmd.util;import java.io.FileOutputStream;import org.dom4j.Document;import org.dom4j.io.OutputFormat;import org.dom4j.io.SAXReader;import org.dom4j.io.XMLWriter;/*** 私有构造器的存在可以让某些类不能被实例化和子类化,* 这些类通常是一些工具类* @author angel11288**/public class XmlDaoUtils {private static Document dom = null;private static String path = XmlDaoUtils.class.getClassLoader()- .getResource("users.xml").getPath();
//私有构造函数的目的:无法被类以外的函数使用,只能通过调用来实现。private XmlDaoUtils(){ }//使XML仅解析一次,要放在静态代码块里static{try {SAXReader reader = new SAXReader();//类加载器,真实路径要分析,要用相对路径dom = reader.read(path);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}public static Document getDom(){return dom;}public static void refXML() {try {XMLWriter writer = new XMLWriter(new FileOutputStream(path), OutputFormat.createPrettyPrint());writer.write(dom);writer.close();} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}}
3、 在com.lmd.test包下开发一个测试类XmlUserTest.java文件:
junit测试包版本不对,会出错。
package com.lmd.test;import org.junit.Test;import com.lmd.dao.XmlUserDao;import com.lmd.domain.User;public class XmlUserTest {@Testpublic void testFindUserByUserName() {XmlUserDao dao = new XmlUserDao();User user = dao.findUserByUserName("admin");System.out.println(user);//admin:admin}@Testpublic void testFindUserByUNandPSW() {XmlUserDao dao = new XmlUserDao();User user = dao.findUserByUNandPSW("admin", "adminXX");System.out.println(user);//admin:admin //null}@Testpublic void testAddUser() {XmlUserDao dao = new XmlUserDao();User user = new User();user.setUsername("张甜");user.setPassword("666666");user.setNickname("小甜甜");user.setEmail("zhangtian8@163.com");dao.addUser(user);//未发布,查看F:\webexample\JAVAWEB\User\WebRoot\WEB-INF\classes下users.xml}}
4、在com.lmd.service包下开发UserService.java: (业务逻辑层)
package com.lmd.service;import com.lmd.dao.XmlUserDao;import com.lmd.domain.User;import com.lmd.exception.MsgException;/*** 业务逻辑层* @author angel11288*/public class UserService {private XmlUserDao dao = new XmlUserDao();/*** 添加用户* @param user* @throws MsgException*/public void registUser(User user) throws MsgException {//1、检查用户名是否已经存在,若存在,则提示if (dao.findUserByUserName(user.getUsername()) != null) {//此处提示,返回值不太好,返回值被占用;可以使用异常机制提示throw new MsgException("用户名已经存在");}//2、若不存在。则调用dao中的方法添加用户dao.addUser(user);}/**检查用户名和密码是否正确** @param username* @param password*/public User isUser(String username, String password) {return dao.findUserByUNandPSW(username, password);}}
5、在com.lmd.service包下开发index.jsp等: (web层:servlet和jsp)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head></head><body><h1>我的网站</h1> <hr><c:if test="${sessionScope.user == null }">欢迎光临!游客!<a href="${pageContext.request.contextPath }/regist.jsp">注册</a><a href="${pageContext.request.contextPath }/login.jsp">登录</a></c:if><c:if test="${sessionScope.user != null }">欢迎回来!${sessionScope.user.username }!<a href="${pageContext.request.contextPath }/LogoutServlet">注销</a></c:if></body></html>
按照调用顺序开发
(1)、开发regist.jsp注册界面,里面有验证码;开发验证码ValiImg.java文件,(并在web.xml中配置,Myeclipse不需要)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><script type="text/javascript">function changeImg(img){//添加后面的时间后,每次点击后,会改变验证码;//地址不变,加一个时间参数,会刷新img.src = "/User/ValiImg?time="+new Date().getTime();}</script></head><body style="text-align:center;"><h1>我的网站_注册</h1> <hr><font color="red">${msg}</font><form action="${pageContext.request.contextPath }/RegistServlet" method="post"><table border="1" align="center"><tr><td>用户名</td><td><input type="text" name="username" value="${ param.username}" /></td></tr><!-- requestScope是所有域属性组成的map;而param是请求参数组成的map --><tr><td>密码</td><td><input type="password" name="password" /></td></tr><tr><td>确认密码</td><td><input type="password" name="password2" /></td></tr><tr><td>昵称</td><td><input type="text" name="nickname" value="${param.nickname }"/></td></tr><tr><td>邮箱</td><td><input type="text" name="email" value="${param.email }"/></td></tr><tr><td>验证码</td><td><input type="text" name="valistr" /></td></tr><tr><td><input type="submit" value="注册" /></td><td><img src="/User/ValiImg" style="cursor:pointer"onclick="changeImg(this)"/></td></tr></table></form></body></html>
开发注册Servlet:RegistServlet.java,其中遇到问题:乱码问题已解决;
验证码出错后回显注册页面(密码除外),之前填写的注册信息消失,要求回显解决:保存请求参数(param)。
封装数据的时候,使用user.setUsername(request.getParameter("username"));若多个属性太复杂,可以使用beanutils包下的BeanUtils.populate(user, request.getParameterMap());
//TAB 右移 ctrl+TAB 左移 ,在User.java中设一个校验数据的方法。
注册成功后,回到注册用户的主页。
package com.lmd.web;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import javax.persistence.metamodel.SetAttribute;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.beanutils.BeanUtils;import com.lmd.domain.User;import com.lmd.exception.MsgException;import com.lmd.service.UserService;/*** Servlet implementation class RegistServlet*/@WebServlet("/RegistServlet")public class RegistServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//TAB 右移 ctrl+TAB 左移try {request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");UserService service = new UserService();//1、检验验证码String valistr = request.getParameter("valistr");String valistr2 = (String) request.getSession().getAttribute("valistr");if (valistr == null || valistr2 == null || !valistr.equals(valistr2)) {request.setAttribute("msg", "验证码不正确");request.getRequestDispatcher("/regist.jsp").forward(request, response);;return;}//2、封装数据,校验数据User user = new User();BeanUtils.populate(user, request.getParameterMap());user.checkValue(); //throw new MsgException//3、调用service中的方法添加用户service.registUser(user); //throw new MsgException//4、登录用户request.getSession().setAttribute("user", user);//5、提示注册成功回到主页response.getWriter().write("恭喜您注册成功!3秒后回到主页...");response.setHeader("Refresh","3;url="+request.getContextPath()+"/index.jsp");} catch (MsgException me) {request.setAttribute("msg", me.getMessage());request.getRequestDispatcher("/regist.jsp").forward(request, response);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
(2)、开发注销LogoutServlet.java
package com.lmd.web;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** Servlet implementation class LogoutServlet*/@WebServlet("/LogoutServlet")public class LogoutServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {if (request.getSession(false)!=null && request.getSession().getAttribute("user")!=null) {request.getSession().invalidate();}response.sendRedirect(request.getContextPath() + "/index.jsp");}protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
(3)、开发登录界面login.jsp和LoginServlet.java,并开发记住用户名(存在Cookie中)功能。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ taglib uri="http://www.lmd.com/UserTag" prefix="UserTag" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head></head><body><div style="text-align: center;"><h1>我的网站_登录</h1> <hr><font color="red">${msg }</font><form action="${pageContext.request.contextPath}/LoginServlet" method="post"><table border="1" align="center"><tr><td>用户名</td><td><input type="text" name="username" value="<UserTag:UserTagcontent="${cookie.remname.value }" encode="UTF-8"/>"/></td></tr><tr><td>密码</td><td><input type="password" name="password"/></td></tr><tr><td><input type="submit" value="登录"/></td><!-- 回显回来,是被勾中的状态 --><td><input type="checkbox" value="ok" name="remname"<c:if test="${cookie.remname != null}">checked="checked"</c:if>/>记住用户名</td></tr></table></form></div></body></html>
package com.lmd.web;import java.io.IOException;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.lmd.domain.User;import com.lmd.service.UserService;/*** Servlet implementation class LoginServlet*/@WebServlet("/LoginServlet")public class LoginServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//以后使用过滤器解全栈乱码request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");UserService service = new UserService();//1、获取客户端提交的用户名和密码String username = request.getParameter("username");String password = request.getParameter("password");//2、调用service中的方法检查用户名和密码User user = service.isUser(username, password);if (user == null) {//3、若不正确,则提示request.setAttribute("msg", "用户名或密码不正确!");request.getRequestDispatcher("/login.jsp").forward(request, response);return;}else {//4、正确回到登录主页request.getSession().setAttribute("user", user);//实现记住用户名:if ("ok".equals(request.getParameter("remname"))) {//若勾住,记住,则发送cookie令浏览器保存用户名//中文有问题,要编码Cookie remNameC = new Cookie("remname",URLEncoder.encode(user.getUsername()));remNameC.setPath(request.getContextPath());remNameC.setMaxAge(3600*30*24);response.addCookie(remNameC);}else {//若不勾住,不记住,则删除记住用户名的cookieCookie remNameC = new Cookie("remname", "");remNameC.setPath(request.getContextPath());remNameC.setMaxAge(0);response.addCookie(remNameC);}response.sendRedirect(request.getContextPath()+"/index.jsp");}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
记住用户名:要求再次回到登录页面,记住了用户名(为了不嵌套java代码,使用自定义标签解码用户名的编码,显示出来)
package com.lm.tag;import java.io.IOException;import java.net.URLDecoder;import javax.servlet.jsp.JspException;import javax.servlet.jsp.tagext.SimpleTagSupport;public class URLEncoderTag extends SimpleTagSupport{private String content;private String encode;public void setContent(String content) {this.content = content;}public void setEncode(String encode) {this.encode = encode;}@Overridepublic void doTag() throws JspException, IOException {//encode设置<required>false</required>,非必须String s = URLDecoder.decode(content, encode == null ? "UTF-8" : encode);getJspContext().getOut().write(s);}}
<?xml version="1.0" encoding="UTF-8"?><taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"><tlib-version>1.0</tlib-version><short-name>UserTag</short-name><uri>http://www.lmd.com/UserTag</uri><tag><name>UserTag</name><tag-class>com.lm.tag.URLEncoderTag</tag-class><body-content>empty</body-content><attribute><name>content</name><required>true</required><rtexprvalue>true</rtexprvalue><type>java.lang.String</type></attribute><attribute><name>encode</name><required>false</required><rtexprvalue>true</rtexprvalue><type>java.lang.String</type></attribute></tag></taglib>












浙公网安备 33010602011771号