一、JSP:java server page
(一)动态web技术:
java+html
1、JSP脚本元素:
(1)jsp声明:<%! %> 全局编码和方法的声明
(2)jsp表达式:<%= %> 输出指定的变量、数据到浏览器
(3)jsp脚本:<% %> 编写合法的java代码
2、JSP指令元素:
(1)page
语法:<%@ page 属性1=value1%>
常用属性:
contentType:响应数据的类型和编码
contentType="text/html;charset=utf-8"\
pageEncoding:页面编码,如果和charset同时存在优先使用pageEncoding
errorPage:指定当前页面发生错误时跳转的页面
isErrorPage:标示该页面是否为错误页面,true(可以使用exception)
import:导入其他类 唯一一个能在page指令中出现多次的属性
import="com.bdyc.po.User"
import="com.bdyc.po.*"
import="com.bdyc.po.*,java.util.*"
language:指定jsp中支持的脚本语言 java
session:true 页面可以使用session内置对象,false 不行
(2)include
语法:静态引入(原样拷贝),先引入再编译(先将页面拷贝到本页面再统一转换编译) 编译后会形成一个文件
<%@ include file="path" %>
作用:用来导入其他的页面内容到本页面
弊端:只要有一个引入的子页面发生改变,系统就会重写编写该文件
好处:只要一个文件
- taglib :jstl el
3、JSP动作元素:
(1)jsp:include
语法:动态引入,先编译再引入(先将子页面转换编译,再将子页面编译后结果引入) 会形成多个文件
<jsp:include page="path"></jsp:include>
作用:引入片段页面
弊端:产生多个文件
好处:
改变子页面不会影响到主页面
可以再引入子页面是为子页面传入自定义参数
(2)jsp:param
该标签不能单独使用,一般和jsp:include结合使用用来给子页面传递参数
<jsp:include page="top.jsp">
<jsp:param value="zhangsan" name="name"/>
</jsp:include>
<%=request.getParameter(name);接受页面参数
(3)jsp:forward(了解)
语法:<jsp:forward page="目标地址"></jsp:forward>
作用:将页面转发到指定页面地址
转发:地址栏不变,内容区为其他页面
(4)jsp:useBean
(5)jsp:setProperty
4、JSP内置对象:(9大内置)
JSP页面内部已经存在的对象,JSP页面内部自带的对象可以直接使用 (js内置:Date window document)
ctrl+shift+t:查看源码
(1)out: 类似<%= %>
类型:javax.servlet.jsp.JspWriter extends Writer(输出流:客户端浏览器)
作用域:page(当前页面有效,一个页面有一个out对象)
常用方法:
print(Object obj):输出任何类型数据到客户端浏览器
write(String str):输出字符到客户端浏览器
(2)page(了解)
类型 :java.lang.Object javax.servlet.jsp.HttpJspPage
作用域:page
(3)request
类型:javax.servlet.http.HttpServletRequest
作用域:request 一次请求(浏览器地址栏只要不变)
常用方法:
String value = request.getParameter(name):接受页面一个参数值,根据参数名出去对应的参数值
String[] values = request.getParameterValues(name):根据参数名出去对应的参数值,接受页面一组参数值(checkbox select)
reqeust.getRequestDispatcher(path).forward(request,response):将页面"转发"到目标地址
request.setAttribute(name,value):向request作用域中添加额外属性
request.getAttribute(name):从request作用域中获取指定属性值
request.setCharacterEncoding("utf-8"):设置请求编码,解决POST请求中文乱码问题
(4)response
类型:javax.servlet.http.HttpServletResponse
作用域:response 一次请求(浏览器地址栏只要不变)
常用方法:
response.setRedirect(path): 将页面"重定向"到目标地址
重定向特点:
1、地址栏改变
2、发送2次请求:response.setRedirect("02.jsp");
①、告诉服务我要02.jsp地址,服务器讲02.jsp页面地址响应回来
②、告诉服务我要02.jsp内容,服务器讲02.jsp页面内容响应回来
response.setCharacterEncoding("utf-8"):设置响应数据编码
(5)session:
类型:javax.servlet.http.HttpSesssion
作用域:一次会话(只要浏览器不关闭) 用来存储用户的状态信息
常用方法:
session.getId():获取sessionId
session.isNew():判断session是否是新建的
session.setAttribute(key,value):向session作用域对象中添加属性值
session.getAttribute(key):从session作用域中的获取值
session.removeAttriute(key):从session作用域中的删除某个属性值
session.setMaxInactiveInteaval(ms):设置session的最大失效时间,默认30分钟 20分钟=60*1000*20
session.invalidate():销毁session(手动终止会话方式)
session的工作原理:
当第一次访问jsp页面时系统会创建一个新的session对象,并在给浏览器响应信息时将JSESSIONID值同时通过cookie形式
传输到浏览器,浏览器保存到本地磁盘(默认保存时间为浏览器关闭)。
当你在没有关闭浏览器的时候再次向服务器发送请求时,浏览器会自动将之前的JSESSIONID存放在请求头中一并发送给服务器
服务器接受到对应的JSESSIONID,检查在session池中是否有对应id的session对象,如果有直接返回对象使用。如果没有
重新创建新的session对象响应给浏览器。
不是浏览器不关闭一定就会获取到上一个session对象,还有看服务中session池的对象是否已经销毁。
session对象销毁的方式只要以下两种:
1、sesion的失效时间到了自动销毁
2、手动调用invalidate()方法销毁。
- Application
类型:javax.servlet.ServletContext
作用域:一次服务关闭(只要服务器tomcat不关闭,对象一直存在)
常用方法:
application.setAttribute(key,value):
application.getAttribute(key,value):
- Config
类型:javax.servlet.ServletConfig
作用域:page
常用方法:
config.getInitParameter(name):
config.getInitParameterValues():
(8)pageContext
类型:javax.servlet.jsp.PageContext
作用域:page
常用方法:
pageContext.getRequest()
pageContext.getResponse();
...
pageContext.setAttribute(key,value):
pageContext.getAttribute(key,value):
- Exception:只有jsp页面设置 isErrorPage=true 才能使用
类型:java.lang.Exception
作用域:page
常用方法:
exception.getMessage():获取异常信息
exception.printStackTrace():打印异常堆栈信息到控制台
**总结4大作用域:
page:当前页面有效
request:一次请求有效(地址栏不变) --保存业务数据
session:一次会话有效(浏览关闭) --保存用户状态信息(一定不能保存业务数据:用户列表 部门类别 商品信息)
application:一次服务器关闭 --保存不经常改变的数据:系统导航
二、请求方式:get、post
1、post:
参数不会拼接到地址栏,会隐藏到http协议体中传递到后台服务器
安全性相对高
参数大小无限制
效率相对低
设置form表单的请求方式:method="post"
2、get
参数会拼接在地址栏中
安全性相对低
参数大小有限制
效率相对高
设置form表单的请求方式:method="get"
超链接请求
直接在地址栏输入地址的请求方式
如何使用:
如果考虑到效率,且没有安全性时首选get
上传:post
参数传递:
后台接受方式:request.getParameter(name) request.getParameterValues(name)
1、使用form表单向后台发送参数
2、使用地址栏拼接形式:
http://localhost:8080/javaWEB06/loginHandle.jsp?username=admin&password=admin123
第一个参数使用?隔开,其它参数使用&隔开
乱码问题解决:
get请求乱码:
原因:get请求默认使用的是tomcat服务器的编码(iso8859-1)
解决方案:
1、系统tomcat的默认编码:utf-8 修改/conf/server.xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="utf-8"/>
2、手动解决
username = new String(username.getBytes("iso8859-1"),"utf-8");
post请求乱码:
解决方案:request.setCharacterEncoding("utf-8");
三、补充:错误页面处理方式
1、为可能发生错误的页面配置:errorPage="page/error/500.jsp"
2、在web.xml中配置:
<error-page>
<error-code>500</error-code>
<location>/page/error/500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/page/error/404.jsp</location>
</error-page>
四、Servlet主要功能:
1、接受页面参数
JSP: request.getParameter(name):
2、调用业务逻辑(service)
3、负责页面跳转(转发和重定向)
JSP: response.sendRedirect(path)
request.getRequestDispatcher(path).forward(request,response)
单例设计模式: 自始至终只要一个对象被创建
1、构造方法私有化
2、提供公有静态成员方法实例化对象
3、私有静态本类类型的变量
懒汉式:
//单例设计模式:懒汉式
public class User {
//私有静态本类类型变量
private static User user;//null
//私有构造
private User(){
}
//公有静态方法:实例化对象
public static User newInstance(){
if(user == null){
user = new User();
}
return user;
}
}
饿汉式:
//单例设计模式:饿汉式
public class User1 {
//私有静态本类类型变量
private static User1 user = new User1();//null
//私有构造
private User1(){
}
//公有静态方法:实例化对象
public static User1 newInstance(){
return user;
}
}
Servlet对象是单例。
在servlet类中能出现可以被修改的成员变量吗?
Servlet是在多线程环境运行时,那就必须要考虑线程安全问题:
1、多线程
2、共享一个资源
3、对共享资源进行了:修改操作
如何解决:只要将上述条件中的任何一个失效
Servlet解决线程安全问题(避免线程安全问题出现)方案:
不要在servlet中出现可以被修改的成员变量。
(一)编写servlet步骤:
1、新建一个类实现Servlet接口
2、配置web.xml:
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.bdyc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!--第一个/:项目根路径
<url-pattern>/helloworld</url-pattern>
<url-pattern>/a/b/c/helloworld</url-pattern>
</servlet-mapping>
3、在地址栏输入:http://localhost:8080/工程名/helloworld http://localhost:8080/工程名/a/b/c/helloworld
Servlet类对象生命周期:默认(重点)
1、当第一次访问该servlet时,系统会自动创建Servlet对象(一次)
2、自动调用init()完成初始化操作
3、每次访问都会调用service()方法,完成业务处理
4、当服务器关闭时会调用destory()方法回收资源,销毁对象。
通过案例分析发现Servlet接口中的很多方法:init destory 等这些方法对我们来说并没有使用,但是每次编写servlet时都要重写。(麻烦)
Tomcat就给我们提供了解决方案:
(二)编写servlet步骤:
1、新建一个类继承GenericServlet,重写service方法(手动类型转换)
参考第一种
service方法中的参数类型不是HttpServletRequest,HttpServletResponse类型,每次使用都要手动转换(麻烦)
Tomcat就给我们提供了解决方案:
(三)编写servlet步骤:
1、新建一个类继承HttpServlet,重写service方法(自动类型转换)
以上几种重写service方法的方式,每次无论客户端发送的是什么格式的请求(get/post)都会交给service方法处理。
但是由于get请求和post处理方式还是有区别的:比如中文乱码处理方式。导致不能很好的区分开get和post。
推荐使用以下方式完成servlet的编写:
(五)最终版:
1、新建一个类继承HttpServlet,重写doGet和doPost方法
public class HelloServlet3 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//处理get请求
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//处理post请求
}
}
总结:
ModelI:JSP+JavaBean
JSP页面中出现了大量的java代码不好维护。
ModelII: JSP+Servlet+JavaBean
将JSP页面中的所有java代码移植到Servlet中
- 过滤器:Listener
如何编写一个过滤器:
1、新建一个类实现javax.servlet.Filter接口
public class EncodingFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
System.out.println("post编码过滤器");
//请求数据处理编码
req.setCharacterEncoding("utf-8");//utf8
chain.doFilter(req, resp);
}
@Override
public void destroy() {
}
}
2、web.xml配置过滤器
<!-- 编码过滤器配置:在其他所有过滤器的最前面 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.bdyc.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、servlet过滤器的API:Filter、FilterChain、FilterConfig
4、过滤器三个方法:①init:web容器调用此方法一次
②doFilter:发送请求时调用
③destory
5、生命周期的四个阶段:
1>实例化:web容器在部署应用程序时对所有过滤器进行实例化,web容器回调它的无参构造;
2>初始化:实例化完成之后,马上进行初始化工作,web容器回调init()方法,执行一次;
3>过滤:请求路径匹配过滤器的URL映射时,web容器回调doFilter()方法,每次请求都执行的主要的方法;
4>销毁:web容器在卸载web应用程序前,web容器回调destory()方法。
- 监听器:Listener
如何编写一个监听器:
1、新建一个类实现ServletContextListener、ServletRequestListener、HttpSessionListener...接口
public class MyListener implements ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request对象销毁");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request对象创建");
}
}
2、web.xml配置监听器
必须在filter和servlet配置之前
<!-- 配置监听器 -->
<listener>
<listener-class>com.bdyc.listener.MyListener</listener-class>
</listener>
3、Listener的初始化比filter和servlet都优先,而销毁比他们都慢。
随着web应用的启动而启动,只初始化一次,随web应用的停止而销毁
七、拦截器和过滤器的区别
1、拦截器是基于java的反射机制的,而过滤器是基于函数回调
2、过滤器依赖与servlet容器,而拦截器不依赖与servlet容器
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
执行顺序 :过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。
个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);
过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;
Action处理完成返回后,拦截器还可以做其他过程,再向上返回到过滤器的后续操作。