第七天的课程主要是讲了自定义标签、简单介绍了mvc设计模式、然后做了案例
1. 自定义标签
1.1 为什么要有自定义标签
前面所说的EL、JSTL等技术都是为了提高jsp的可读性、可维护性、方便性而取代在jsp页面中直接嵌入java代码的方式(el和jstl的实质也是一段Java代码,只是可以用他们来代替),但是在实际开发过程中业务非常的复杂,现有的el和jstl根本满足不了需求,所有得根据实际需求开发自己的标签,自定义标签应运而生。
1.2 自定义标签分类(传统标签和简单标签)
自定义标签分为两类:传统标签(继承tag接口)和简单标签(继承simpleTagSupport接口),实现的步骤同实现el函数一样。第一步就是写一个类,第二步就是定义一个tld文件对类中的方法和属性进行描述,第三步就是在jsp文件中对定义的tld文件进行引用。
1.2.1 传统标签
1.2.1.1 传统标签继承tag接口,里面有些重写方法setPageContext(可以用来初始化pageContext)、setParent(设置父标签)、doStartTag、doEndTag(这两个方法是最重要的两个方法,标签的实际功能就是在两个方法中定义的)
1.2.1.2 Eval_Body、Skip_Body、Skip_Page、Eval_page 这个是doStartTag、doEndTag这两个方法的返回值,能控制标签的body和剩余page是否计算
1.2.1.3 案例自定义一个showip的标签
package com.chenlh.prac; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; public class ShowIP implements Tag { private PageContext pc = null; @Override public int doEndTag() throws JspException { // TODO Auto-generated method stub return 0; } @Override public int doStartTag() throws JspException { try { String ip = pc.getRequest().getRemoteAddr(); pc.getOut().write(ip); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return 0; } @Override public Tag getParent() { // TODO Auto-generated method stub return null; } @Override public void release() { // TODO Auto-generated method stub } @Override public void setPageContext(PageContext arg0) { // TODO Auto-generated method stub pc = arg0; } @Override public void setParent(Tag arg0) { // TODO Auto-generated method stub } }
1.2.2 简单标签
步骤:第一步,写一个类实现simpleTagSupport接口;第二步,写一个tld文件对类进行描述;第三步,在jsp页面中文tld文件进行引用
案例:自定义一个showip的简单标签
package com.chenlh.prac; import java.io.IOException; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.JspTag; import javax.servlet.jsp.tagext.SimpleTag; public class SimpleShowIp implements SimpleTag { private PageContext pc = null; @Override public void doTag() throws JspException, IOException { // TODO Auto-generated method stub String ip = pc.getRequest().getRemoteAddr(); pc.getOut().write(ip); } @Override public JspTag getParent() { // TODO Auto-generated method stub return null; } @Override public void setJspBody(JspFragment arg0) { // TODO Auto-generated method stub } @Override public void setJspContext(JspContext arg0) { // TODO Auto-generated method stub pc = (PageContext)arg0; } @Override public void setParent(JspTag arg0) { // TODO Auto-generated method stub } }
2. mvc设计模式
2.1 Java web的发展史(才有了mvc设计模式)
2.1.1 servlet
servlet是sun公司提供的最早的javaweb技术,它有一个缺点就是Java代码中编写html代码很不方便。
2.1.2 jsp(实质也是一个servlet,第一次访问的时候会被翻译成一个servlet)
基于servlet在Java代码中编写html代码很不方便的毛病,jsp应运而生,它能很方便的编写html代码同时还能嵌入Java代码
2.1.3 jsp + javabean(模式一) ps:jsp包含标签技术
久而久之发现在jsp中嵌入大量的Java代码,可读性不是很好,于是就有标签技术,而且jsp本身就是一个servlet于是就才用jsp+javabean的模式
2.1.4 servlet+jsp +javabean(模式二)
模式一又发展了一段时间,设计者发现jsp的特长就是向用户展示数据的,而现在又担任了servlet程序流转的工作,没有做到无尽期能,各司所职的目的,于是就有了模式二。
2.1.5 javaweb经典一层架构(mvc设计模式)
任何软件都可以看做是由如下三个模块组成的。控制器:用来控制程序流转;view:用来与用户进行交互;model:用来封装数据和处理业务逻辑(一个设计良好的软件都应该尽力将这三部分独立开来)
2.2 Javabean
2.2.1 什么是javabean
javabean是一个遵循特定写法的类
2.2.2 javabean特点
2.2.2.1 它必须有一个无参的构造函数
2.2.2.2 属性必须私有化
2.2.2.3 私有属性必须通过一个public类型的方法暴露给其它程序,并且方法名必须遵循一定的命名规范
3.案例
3.1 用户注册登录注销(模式二实现:servlet+jsp+javabean+dom4J(xpath)+junit)
用户注册登录注销主要的功能点:用户注册、用户登录、用户注销、记住用户名。知识点:XML的操作(这里用xml模拟数据库所以有dom4J的使用)、session应用(登录成功后保存用户数据)、cookie(记住用户名实质就是向客户端写一个cookie)、自定义标签(记住用户名时用户名可能是中文所以需要Decoder而此时又不想在页面中嵌入大量的Java代码)
jar包:Junit,dom4J,*jstl,beanutils
实现过程:
编程思想总结:各个模块尽量解耦,各司其职。如业务层不要出现SQL语句(因为有可能换成其他的数据库或者多数据库共用),DAO层不要出现页面上的提示信息,因为你不知道将来页面的提示信息要改什么样的。
Xpath:Xpath的作用是用来检索dom文件的(xml文件加载成dom),它需要jaxen(jar包)的支持,用SaxReader解析xml
3.1.1 注册 ps:throw new exception 之后的代码段将不再执行,抛走了;session丢失可能是没有存,或者客户端禁用了cookie
3.1.1.1 判断验证码
生成验证码并将验证码返回给浏览器的同时,也将它保存到session中,如果验证码不正确则转发到注册页面
3.1.1.2 封装验证数据(直接放在javabean中验证) ps:这里用一个beanutils工具类,其中的popular方法能自动填充map数据到javabean中
将数据封装到一个javabean里面,如果不正确就抛出异常,在这里需要一个必须被捕捉和处理的异常(自定义一个MsgException类) ,如果外层捕捉到异常
则将抛出的异常信息通过转发打印到注册页面上
PS:RunTimeException和Exception的区别就是RunTimeException不需要外层捕捉和处理,而Exception需要被捕捉和处理
3.1.1.3 判断用户名是否已经注册
如果用户名已经被注册,同样是抛出一个MsgException自定义的异常不过在抛出这个异常的时候也要通过throws在方法前面声明
3.1.1.4 注册用户
当上面的步骤都通过了,那么就可以向数据库中注册用户了。PS:这里是xml中添加一个user节点。首先将xml加载到dom中,然后获取root节点,然后声明 一个element将注册信息setAttribute上,再将element附加到root根节点上,由于dom是一个引用类型,此时只需要利用xmlWriter将dom写入文件即可
3.1.2 登录(记住用户名)
3.1.2.1 校验用户名和密码
校验成功后,将用户信息存session中,在需要用户登录才能访问的页面判断有没有session信息即可
3.1.2.2 是否记住用户名
PS:<input type="checkbox" value="ok">如果勾选上,则会将value值以表单的形式传到服务器,否则不传。(这里可以用chrome F12观察一下)
3.1.2.2.1 勾选上:如果勾选上了,则要实例化一个cookie对象,并设置path和setMaxAge属性并添加到response中(这里有个问题就是当用户名为中文的时候返回 cookie,当cookie再次发送到服务器时会因为乱码导致服务器错误,而setContentType("text/html;charset=utf-8")只对页面content有效,所以这里必须要用UrlEncoder对用户名进行编码,同时页面上获取的时候需要解码,但是我又不想在jsp中写大量的Java代码,所以此时想到了自定义标签)
自定义标签三步骤:第一步,继承simpleTagSupport接口,重新dotag方法;第二步,定义描述tld文件;第三步页面引用
ps:这里还有小细节就是当有cookie那么用户在登录界面的时候记住用户名复选框一定要勾上
3.1.2.2.2 记住用户名没有勾选:那么只要删除cookie即可
删除cookie的方法:声明一个同名同path的cookie并将setMaxAge设置成0即可然后添加到response中
3.1.3 注销
这个环节就比较简单了,其实就是将session杀死调用request.getSession().invaidate()
Ps:request.getSession()默认情况下如果有session对象则返回一个,如果没有则创建一个session对象;而request.getSession(false)如果有就返回session对象,如果没有也不会创建了。