为了解决web资源开发技术:演变过程
一、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可以有
多个属性。每个属性通常都需要具有相应的s
etter、 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:s
etProperty
>
标签
(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.dao com.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());
//TAB 右移 ctrl+TAB 左移 ,在User.java中设一个校验数据的方法。
注册成功后,回到注册用户的主页。
(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; } @Override public 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.xx if (!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 { @Test public void testFindUserByUserName() { XmlUserDao dao = new XmlUserDao(); User user = dao.findUserByUserName("admin"); System.out.println(user); //admin:admin } @Test public void testFindUserByUNandPSW() { XmlUserDao dao = new XmlUserDao(); User user = dao.findUserByUNandPSW("admin", "adminXX"); System.out.println(user); //admin:admin //null } @Test public 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:UserTag content="${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 { //若不勾住,不记住,则删除记住用户名的cookie Cookie 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; } @Override public 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/j2ee http://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>
转载于:https://www.cnblogs.com/angel11288/p/dda1d00a38723b0415d45c6b8352ec08.html