JavaSE 的源码,字节码在哪
JavaEE 版本号
Java EE 的源码,字节码在哪里
系统架构分类
Servlet.java
/*
SUN公司制定的JavaEE规范:Servlet规范
Servlet接口是Servlet规范中核心接口
接口注意:调用者谁?实现者谁?
*/
// 服务器端的java程序不能随意编写,必须实现Servlet接口
public interface Servlet{
/*
服务器端的java小程序必须将service方法实现
*/
void service();
}
编写服务器端java小程序时,不能随意编写,必须实现Servlet接口
LoginServlet.java
public class LoginServlet implements Servlet{
public void service(){
System.out.println("连接数据库验证登陆密码");
}
}
DeleteServlet.java
public class DeleteServlet implements Servlet{
public void service(){
System.out.println("连接数据库删除");
}
}
SaveServlet.java
public class SaveServlet implements Servlet{
public void service(){
System.out.println("连接数据库保存");
}
}
web.xml
在这里维护路径和 servlet 之间的关系
由 JavaWeb程序员编写
/login = LoginServlet
/save = SaveServlet
/delete = DeleteServlet
Tomcat.java
/*
Tomcat
WebServer
Web 服务器
Web Container
Web 容器
*/
import java.util.Scanner;
import java.util.Properties;
import java.io.FileReader;
public class Tomcat{
public static void main(String[] args) throws Exception{
Scanner s = new Scanner(System.in);
System.out.println("--服务器启动成功--");
// 使用while来保持一直可以输入的状态
while(true){
System.out.println("---请输入请求路径:");
// 程序执行到这里,等待用户的访问
String requestPath = s.next();
System.out.println("您访问的资源路径时:" + requestPath);
// Tomcat 读取 web.xml 文件
FileReader reader = new FileReader("web.xml");
Properties pro = new Properties();
pro.load(reader);
reader.close();
// 通过 key(请求路径) 获取 value(编写的Servlet)
String servletClassName = pro.getProperty(requestPath);
// 通过反射机制创建对象
Class c = Class.forName(servletClassName);
// Object obj = c.newInstance();
// 由于都实现了Servlet接口,可以直接强转为 Servlet
Servlet servlet = (Servlet)c.newInstance();
// 面向Servlet接口调用方法
servlet.service();
}
}
}
javac *.java
编译Java文件java Tomcat
启动Tomcat主类Tomcat 7
tomcat --> webapps --> FirstWebApp --> login.html
tomcat --> webapps --> FirstWebApp --> html --> welcome.html
重启tomcat即可访问tomcat对应目录下的网页
同上
新建目录
tomcat --> webapps --> FirstServletWebApp
FirstServletWebApp
编写Servlet
HelloServlet.java
将编译过的class文件放到上面的classes文件夹中
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class HelloServlet implements Servlet{
public void init(ServletConfig config) throws ServletException{
}
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
System.out.println("Hello World");
}
public void destroy(){
}
public String getServletInfo(){
return null;
}
pubilc ServletConfig getServletConfig(){
return null;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 这是一个合肥的web.xml文件 -->
<!-- 一个webapp只有一个web.xml文件 -->
<!-- web.xml文件主要配置请求路径和Servlet类名之间的绑定关系 -->
<!-- web.xml文件在Tomcat服务器启动阶段被解析 -->
<!-- web.xml文件解析失败,会导致webapp启动失败 -->
<!-- web.xml文件中的标签不能随意编写,因为tomcat服务器知道该文件中编写了哪些标签 -->
<!-- web.xml文件中的标签也是SUN公司制定的Servlet规范 -->
<servlet>
<servlet-name>thisIsServletName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>thisIsServletName</servlet-name>
<!-- 路径随意编写,但是必须以 / 开始 -->
<!-- 这个路径是一个虚拟的路径,只是代表一个资源的名称 -->
<url-pattern>/hel/lo/he</url-pattern>
<!-- 可以编写多个url-pattern,路径需要以 / 开始 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
tomcat --> webapps --> PrintToBrowser
**PrintToBrowser **
编写Servlet
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;// 标准输出流,不需要关闭
public class WelcomeServlet implements Servlet{
public void init(ServletConfig config) throws ServletException{
}
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
// 解决响应的时候中文乱码问题
// 设置响应的内容类型以及字符编码方式
// 在获取响应流之前设置
response.setContentType("text/html;charset=UTF-8");
// 将信息输出到浏览器上
// 将HTML字符串输出到浏览器上,浏览器解析执行
// 获取输出流对象,流直接指向特定的浏览器客户端
PrintWriter out = response.getWriter();
// 这是再设置的话就晚了,一定要在前面设置
// response.setContentType("text/html;charset=UTF-8");
// 响应html代码到浏览器
out.print("<html>");
out.print("<head>");
out.print("<title>welcome servlet</title>");
out.print("</head>");
out.print("<body>");
out.print("<h1 align=\"center\">welcome study servlet</h1>");
out.print("</body>");
out.print("</html>");
// ln表示将HTML源代码换行,这个没有必要,反而使得html体积变大
/*
out.println("<html>");
out.println("<head>");
out.println("<title>welcome servlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1 align=\"center\">welcome study servlet</h1>");
out.println("</body>");
out.println("</html>");
*/
}
public void destroy(){
}
public String getServletInfo(){
return null;
}
pubilc ServletConfig getServletConfig(){
return null;
}
}
web.xml 同上节
什么是生命周期
生命周期表示一个java对象从最初被创建到最终被销毁,经历的所有过程
Servlet对象的生命周期是谁来管理的?程序员可以干涉吗?
Servlet对象的生命周期,JavaWeb程序员是无权干涉的,包括该Servlet对象相关方法的调用,也是无权干涉的 。
Servlet对象从最初的创建开始,方法的调用,以及最后对象的销毁,整个过程,都是由Web容器来管理的。
Web Container 管理Servlet生命周期
默认情况下,Servlet对象在Web服务器启动阶段不会被实例化。【若希望在web服务器启动阶段实例化Servlet对象,需要进行特殊的设置】
http://localhost:8080/prj/testlifecycle
/prj/testlifecycle
/prj/testlifecycle
对应的Servlet对象/testlifecycle
对应的Servlet完整类名init
方法完成初始化操作service
方法提供服务service
方法提供服务destroy
方法,完成销毁之前的准备。总结
注意
init方法执行的时候,Servlet对象已经被创建好了
destroy方法执行的时候,Servlet对象还没有被销毁,即将被销毁
Servlet对象是单例,但是不符合单例模式,只能称为伪单例。真单例的构造方法是私有化的。Tomcat服务器是支持多线程的,所以Servlet对象在单实例多线程的环境下运行。那么Servlet对象中若由实例变量,并且实例变量涉及到修改操作,那么这个Servlet对象一定会存在线程安全问题,不建议在Servlet对象中使用实例变量,尽量使用局部变量。
若希望在web服务器启动阶段实例化Servlet对象,需要在web.xml文件中进行相关的配置,load-on-startup
,越小优先级越高,例如:
<servlet>
<servlet-name>testlifecycle</servlet-name>
<servlet-class>com.bj.javaweb.servlet.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Servlet对象实例化之后,这个Servlet对象被存储到哪里了
大多数的web容器都是将该Servlet对象以及对应的url-pattern存储到Map集合中了
在WEB容器中由这样一个Map集合
Map<String, Servlet> 集合
key | value |
---|---|
/login | LoginServlet对象引用 |
/delete | DeleteServlet对象引用 |
/save | SaveServlet对象引用 |
服务器在启动的时候就会解析各个webapp的web.xml文件,做了什么
将web.xml文件中的url-pattern 和对一个的 Servlet 完整类名存储到Map集合中:
在web容器中由这样一个map集合
Map<String,String> 集合
key | value |
---|---|
/login | com.bj.javaweb.servlet.LoginServlet |
/delete | com.bj.javaweb.servlet.DeleteServlet |
/save | com.bj.javaweb.servlet.SaveServlet |
Servlet接口中的这些方法中填写什么代码?什么时候使用这些方法
无参构造方法 【尽量别动构造函数】
init方法
以上两个方法执行时间几乎是相同的,执行次数都是一次,构造方法执行时对象正在创建,init方法执行时对象已经创建:
若系统要求在对象创建时刻执行一段特殊的程序,这段程序尽量写道init方法中。
为什么不建议将代码编写到构造函数中:
存在风险!当程序员编写构造方法的时候,可能会导致无参构造方法不存在。(类不编写任何构造函数,默认又一个无参构造函数,但编写了一个有参构造方法后,系统就不提供无参构造方法了)
init方法时为javaweb程序员提供的一个初始化时刻。
service方法
这个方法必然要重写,因为需要完成业务逻辑的处理,请求的处理以及完成响应
destroy方法
也是为javaweb程序员提供的一个特殊时刻,被称为对象的销毁时刻
回顾
类加载时刻执行程序,代码写到哪里? -------编写到静态代码块中
AServlet
public class HelloServlet implements Servlet{
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException{
// 目的:在service方法中也能使用 ServletConfig
this.config = config;
System.out.println("AServlet‘s ServletConfig = " + config.toString());
}
@Override
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
System.out.println("Hello World");
}
@Override
public void destroy(){
}
@Override
public String getServletInfo(){
return null;
}
// 给子类调用,在子类中若想获取ServletConfig,可以调用这个方法
@Override
pubilc ServletConfig getServletConfig(){
return config;
}
}
**研究 javax.servlet.ServletConfig 接口: **
javax.servlet.servletConfig
是接口
Apache Tomcat 服务器实现了 Servlet 规范,Tomcat服务器专门写了以个ServletConfig接口的实现类【作为了解,主要是思想】
实现类的完整类名:org.apache.catalina.core.StandardWrapperFacade
javaweb程序员编程的时候,一直是面向ServletConfig接口去完成调用,不需要关心具体的实现类。
Webapp 放到 Tomcat服务器中,ServletConfig的实现类是:org.apache.catalina.core.StandardWrapperFacade
Webapp 放到 JBOSS 服务器中,ServletConfig的实现类可能是另外一个类名
这些所有的实现类,我们都不需要关心,只需要学习ServletConfig接口中有哪些可以使用的方法。
Tomcat服务器是一个实现了Servlet规范和JSP规范的容器
ServletConfig接口中有哪些常用的方法?
ServletConfig到底是什么
如何将init方法上的ServletConfig参数移动到 service 方法中?因为我们程序员主要编写的方法是 service方法,在 service方法中,我们可能要使用 ServletConfig
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>thisIsServletName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
<!-- 初始化参数:被封装到 ServletConfig对象中了 -->
<init-param>
<para-name>driver</para-name>
<para-value>com.mysql.jdbc.Driver</para-value>
</init-param>
<init-param>
<para-name>url</para-name>
<para-value>jdbc:mysql://localhost:3366/x</para-value>
</init-param>
<init-param>
<para-name>user</para-name>
<para-value>root</para-value>
</init-param>
<init-param>
<para-name>password</para-name>
<para-value>1234</para-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>thisIsServletName</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
ServletConfig接口中有哪些常用的方法
String getInitParameter(String name)
通过初始化参数的name获取value
Enumeration getInitParameterNames()
获取所有初始化参数的name
ServletContext getServletContext()
获取 ServletContext【Servlet上下文】对象
String getServletName()
获取servletName <servlet-name>servletName</servlet-name>
public class HelloServlet implements Servlet{
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException{
this.config = config;
}
@Override
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
// 获取ServletConfig
ServletConfig config = getServletConfig();
// 通过初始化参数的name获取value
String driver = config.getInitParameter("driver");
String url = config.getInitParameter("url");
String user = config.getInitParameter("user");
String password = config.getInitParameter("password");
response.setContentType("text/html;charset=UTF-8");
PrintWrite out = response.getWriter();
out.print(driver);
out.print(url);
out.print(user);
out.print(password);
// 获取所有初始化参数的name
Enumeration<String> names = config.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = config.getInitParameter(name);
//...config.getInitParameter("xxx")...
}
// 获取servletName
String servletName = config.getServletName();
out.print("<servlet-name>" + servletName + "</servlet-name");
// 先记住这个方法,后面讲什么是ServletContext
ServletContext application = config.getServletContext();
out.print(application.toString());// org.apache.catalina.core.ApplicationContextFacade@e45ea8
}
@Override
public void destroy(){
}
@Override
public ServletConfig getServletConfig(){
return config;
}
@Override
public String getServletInfo(){
return null;
}
}
AServlet.java
public class AServlet implements Servlet{
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException{
this.config = config;
}
@Override
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
// 获取 ServletConfig
ServletConfig config = getServletConfig();
// 获取ServletContext
ServletContext application = config.getServletContext();
System.out.println("AServlet‘s ServletContext = " + application);
// 打印 AServlet‘s ServletContext = org.apache.catalina.core.ApplicationContextFacade@7e89f2
}
@Override
public void destroy(){
}
@Override
public ServletConfig getServletConfig(){
return config;
}
@Override
public String getServletInfo(){
return null;
}
}
BServlet.java
public class BServlet implements Servlet{
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException{
this.config = config;
}
@Override
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
// 获取 ServletConfig
ServletConfig config = getServletConfig();
// 获取ServletContext
ServletContext application = config.getServletContext();
System.out.println("BServlet‘s ServletContext = " + application);
// 打印 AServlet‘s ServletContext = org.apache.catalina.core.ApplicationContextFacade@7e89f2
}
@Override
public void destroy(){
}
@Override
public ServletConfig getServletConfig(){
return config;
}
@Override
public String getServletInfo(){
return null;
}
}
打印结果一样,两个 Servlet获取的是同一个ServletContext
javax.servlet.ServletContext接口,Servlet规范
Tomcat服务器对ServletContext接口实现类的完整类名:org.apache.catalina.core.ApplicationContextFacade
JavaWeb程序员只需要面向ServletContext接口调用方法接口,不用关心Tomcat具体的实现
ServletContext到底是什么?什么时候创建?什么时候被销毁?创建几个?
ServletContexte接口中常用的方法有哪些?
Object getAttribute(String name)
从 ServletContext 中获取数据
void setAttribute(String name, Object object)
向 ServletContext 中添加数据
void removeAttribute(String name)
移除 ServletContext 中的数据
String getInitParameter(String name)
Enumeration getInitParameterNames()
String getRealPath(String path)
Servlet, ServletConfig, ServletContext 之间的关系?
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- web.xml 文件中配置上下文参数,这些信息被自动封装到ServletContext对象中 -->
<context-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123</param-value>
</context-param>
<servlet>
<servlet-name>thisIsServletName</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>thisIsServletName</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
Servlet.java
public class BServlet implements Servlet{
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException{
this.config = config;
}
@Override
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
// 获取 ServletConfig
ServletConfig config = getServletConfig();
// 获取ServletContext
ServletContext application = config.getServletContext();
// 获取所有上下文初始化参数的name
Enumeration<String> names = application.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
// 通过上下文初始化的name获取对应value
String value = application.getInitParameter(name);
}
// 获取文件的绝对路径
String realPath = application.getRealPath("/index.html");
System.out.println(realPath);
// 打印 C:\tomcat7\webapps\prj\index.html
}
@Override
public void destroy(){
}
@Override
public ServletConfig getServletConfig(){
return config;
}
@Override
public String getServletInfo(){
return null;
}
}
ServletContext 范围可以完成跨用户传递数据
总结
到目前位置,所有编写过的路径:
超链接
<a href="/webappname/doSome"></a>
web.xml 中的 url-pattern
<url-pattern>/doSome</url-pattern>
form 表单的 action 属性
<form action="/webappname/doSome"></form>
String realPath = application.getRealPath("/WEB-INF/resources/db.properties");
关于一个 webapp 欢迎页面的设置:
欢迎页面怎么设置?
假设在WebRoot目录下创建 login.html,想让 login.html 作为整个webapp的欢迎页面,应该做这样的设置, 编写web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 欢迎页面的设置 -->
<welcome-file-list>
<welcome-file>login.html</welcome-file>
<welcome-file>html/welcome.html</welcome-file>
</welcome-file-list>
<!--
<welcome-file-list>
<welcome-file>system/welcome</welcome-file>
</welcome-file-list>
-->
<servlet>
<servlet-name>welcome</servlet-name>
<servlet-class>com.bj.javaweb.servlet.WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>welcome</servlet-name>
<url-pattern>/system/welcome</url-pattern>
</servlet-mapping>
</web-app>
为什么设置欢迎页面?
http://localhost:8080/prj/
直接访问的就是 login.html欢迎页面可以设置多个,越靠上面的优先级越高
上面的配置,优先选择login.html,若这个资源不存在,才会选择welcome.html
注意:欢迎页面设置的时候,路径不需要以 “/” 开始
<welcome-file>login.html</welcome-file>
要求在webapp的根目录下,必须有一个文件,叫做 login.html
<welcome-file>html/welcome.html</welcome-file>
要求在webapp的根目录下,必须有一个文件夹,叫做html,该文件夹中必须有一个文件叫做:welcome.html
一个webapp的欢迎页面不一定是一个HTML资源,可以是任意一种类型的web资源,欢迎页面可以是Servlet
欢迎页面包括全局配置和局部配置
注意:就近原则,局部配置优先级大于全局配置
在一些错误发生之后,统一进行错误的处理,可以在 web.xml 文件中做以下配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>welcome</servlet-name>
<servlet-class>com.bj.javaweb.servlet.WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>welcome</servlet-name>
<url-pattern>/system/welcome</url-pattern>
</servlet-mapping>
<!-- 配置 -->
<error-page>
<error-code>404</error-code>
<location>/error/error.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/error.html</location>
</error-page>
</web-app>
路径总结
public interface CommonIn{
void m1();
void m2();
void m3();
void m4();
void m5();
void m6();
}
public class A implements CommonIn{
@Override
public void m1(){
// doSome
};
@Override
public void m2(){};
@Override
public void m3(){};
@Override
public void m4(){};
@Override
public void m5(){};
@Override
public void m6(){};
}
public class B implements CommonIn{
@Override
public void m1(){};
@Override
public void m2(){
// doSome
};
@Override
public void m3(){};
@Override
public void m4(){};
@Override
public void m5(){};
@Override
public void m6(){};
}
代码冗余
public interface CommonIn{
void m1();
void m2();
void m3();
void m4();
void m5();
void m6();
}
public abstract class Adapter implements CommonIn{
@Override
abstract public void m1(){};
@Override
abstract public void m2(){};
@Override
public void m3(){};
@Override
public void m4(){};
@Override
public void m5(){};
@Override
public void m6(){};
}
public class A extends Adapter{
@Override
public void m1(){
// doSome
};
@Override
public void m2(){
// doSome
};
}
public class B extends Adapter{
@Override
public void m1(){
// doSome
};
@Override
public void m2(){
// doSome
};
}
GenericServlet.java
/**
* GenericServlet 是一个适配器,这个适配器是一个Servlet
* 以后无需直接实现Servlet接口,直接集成这个适配器即可。重写 service方法
*/
public abstract class GenericServlet implements Servlet{
private ServletConfig config;
// 设置成final,防止子类重写,config就无法赋值了
@Override
public final void init(ServletConfig config) throws ServletException{
this.config = config;
this.init();
}
// 建议重写一个无参的init初始化方法给子类重写
public void init(){
}
@Override
abstract public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{}
@Override
public void destroy(){
}
@Override
public String getServletInfo(){
return null;
}
@Override
pubilc ServletConfig getServletConfig(){
return config;
}
// ------- 以下所有方法都是扩展方法,方便子类的使用 ------
public ServletContext getServletContext(){
return getServletConfig.getServletContext();
}
}
HelloServlet.java
public class HelloServlet extends GenericServlet{
@Override
public void init(){
System.out.println("HelloServlet init ...");
}
@Override
public void service(ServletRequest request,ServletResponse response) throws IOException,ServletException{
// doService
}
}
HTTP协议的详细内容
请求协议包括4部分
请求行 包括:请求方式 URI 协议版本号
空白行:专门用来分离消息报头和请求体的
响应协议包括4部分
状态行:协议版本号 状态码 状态描述信息
空白行:专门用来分离响应报头和响应体的
响应协议中重点掌握状态码 200 404 500
GET 和 POST 的区别
浏览器将资源缓存之后,缓存的资源是和某个特定的路径绑定在一起,只要浏览器再发送这个相同的请求路径,这时候就会去缓存中获取资源,不再访问服务器,以这种方式降低服务器的压力,提高用户的体验。
但是有的时候,我们不希望走缓存,希望每一次都访问服务器,可以在请求路径后面添加时间戳,例如:http://ip:port/oa/system?timestamp=1233241432
【JS获取毫秒:new Date().getTime();
】
前端的页面发送的请求方式应当与服务器端需要的请求方式一致。
如何完成以上需求?
在javaweb程序中想办法获取该请求是什么类型的请求,POST 还是 GET?
当外卖获取到请求方式之后,在javaweb程序中可以使用java语言中 if语句进行判断
if("POST".equals(method)){
//doPost
}else if("GET".equals(method)){
//doGet
}
怎么在javaweb中获取请求方式
javax.servlet.http.HttpServletRequest
对象中String getMethod();
可以获取请求方式。public interface HttpServletRequest extends ServletRequest
LoginServlet.java
public class LoginServlet extends GenericServlet{
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{
// 将ServletRequest,ServletResponse强制类型转换成带有Http的接口类型
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 获取浏览器发送的请求方式
String method = request.getMethod();
//System.out.println(method);// GET 或 POST
//LoginServlet 是处理登陆的,要求前端必须发送POST请求
if("GET".equals(method)){
//后台报错
out.print("405---您应该发送POST请求");
throw new RuntimeException("405---您应该发送POST请求");
}else if("POST".equals(method)){
// 程序正常执行
out.print("success...正在登陆...");
}
}
}
上节在每一个Servlet中都编写了以下程序阿里保证前端的请求方式和后台需要的请求方式保持一致。
HttpServletRequest request = (HttpServletRequest)req;
String method = request.getMethod();
if("GET".equals(method)){
//doGet
}else if("POST".equals(method)){
//doPost
}
以上代码在每个Servlet类中都要编写,怎样能封装一下才能不写这样的代码
HttpServlet.java
public class HttpServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletRequest res) throws ServletException,IOException{
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
service(request,response);
}
public void service(HttpServletRequest request,HttpServletRequest response) throws ServletException, IOException{
String method = request.getMethod();
if("GET".equals(method)){
doGet(request,response);
}else if("POST".equals(method)){
doPost(request,response);
}
}
public void doGet(HttpServletRequest request,HttpServletRequest response) throws ServletException, IOException{
response.setContextType("text/html;charset=UTF-8");
PrintWriter out = resposne.getWriter();
out.print("405-您应该发送POST请求");
throw new RuntimeException("405-您应该发送POST请求");
}
public void doPost(HttpServletRequest request,HttpServletRequest response) throws ServletException, IOException{
response.setContextType("text/html;charset=UTF-8");
PrintWriter out = resposne.getWriter();
out.print("405-您应该发送GET请求");
throw new RuntimeException("405-您应该发送GET请求");
}
}
LoginServlet.java
public class LoginServlet extends HttpServlet{
@Override
public void doPost(HttpServletRequest request,HttpServletRequest response) throws ServletException, IOException{
response.getWriter().print("login...");
}
}
重点
编写一个Servlet类应当集成HttpServlet,get请求就重写 doGet方法,post请求就重写 doPost方法
doPost/doGet 方法可以等同看做main方法
当浏览器发送的请求方式和后台的处理方式不同的话,会出现一个错误,405
使用模板方法设计模式
/**
* 模板方法设计模式,可以做到在不改变算法的前提之下,可以重新定义算法步骤的具体实现。
*/
public abstract class PersonTemplate{
/**
* templateMethod是一个模板方法,定义核心算法骨架,具体的实现步骤延迟到子类中完成
* 算法为了受到保护,所以模板方法一般都被final修饰
* 核心算法骨架不需要每一次都编写,这个核心算法只在模板方法中编写了一次。
*/
public final void templateMethod(){
// 核心算法骨架
do1();
do2();
do3();
}
// 下面是具体的实现步骤之一,具体的实现步骤可以延迟到子类中完成,方法通常是抽象方法
public abstract void do3(){
}
public abstract void do2(){
}
publc abstract void do1(){
}
}
public class Student extends PersonTemplate{
@Override
public void do1(){
System.out.println("学生-上学");
}
@Override
public void do2(){
System.out.println("学生-上课");
}
@Override
public void do3(){
System.out.println("学生-放学");
}
}
public class Worker extends PersonTemplate{
@Override
public void do1(){
System.out.println("工人-上班");
}
@Override
public void do2(){
System.out.println("工人-工作");
}
@Override
public void do3(){
System.out.println("工人-下班");
}
}
public class Test{
public static void main(String[] args){
PersonTemplate p1 = new Student();
p1.templateMethod();
PersonTemplate p2 = new Worker();
p2.templateMethod();
}
}
项目中哪里见过模板方法设计模式
Servlet规范中的:HttpServlet
HttpServlet是一个典型的模板方法设计模式
HttpServlet是一个模板类
其中的service(HttpServletRequest,HttpServletResponse)
方法是典型的模板方法
在该方法中定义了核心算法骨架,doGet,doPost, ... 具体实现步骤延迟到子类中完成。
研究:javax.servlet.http.HttpServletRequest
接口
HttpServletRequest 是一个接口,Servlet规范中重要的接口之一。
继承关系
public interface HttpServletRequest extends ServletRequest{}
HttpServletRequest 接口的实现类是Web容器(Tomcat)负责实现的。但是程序员还是只需要面向HttpServletRequest接口调用方法即可,不需要关心实现类。
HttpServletRequest 对象中封装了哪些信息
HttpServletRequest一般变量名叫:request,表示请求。HttpServletRequest对象代表一次请求,一次请求对应一个request对象,100个请求对应100个request对象,所以request的生命周期是短暂的。
HttpServletRequest接口中常用的方法
表单提交的数据信息会被自动封装到request对象中,request对象中有Map集合存储这些数据【Map集合的key是name,value是一个字符串类型的一维数组】
String getParameter(String name)
通过key获取value这个一维数组中的首元素(通常情况下这个一维数组中只有一个元素,所以这个方法使用最多)
Map getParameterMap()
获取整个Map集合
Enumeration getParameterNames()
获取整个Map集合的所有key
String[] getParameterValues(String name)
通过Map集合key获取value(一维数组)
public class SaveUserServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 获取用户信息,表单提交的,这些数据信息被自动封装到request对象中了
// 从request中获取这些信息
// 表单数据是这样的格式提交的,POST请求,在请求体中提交,数据格式:
// username=admin&password=123&sex=m&...
/*
* Map<String,String[]>
key value
--------------------------------
username {"admin"}
password {"123"}
sex {"m"}
interest {"sport","music"}
... ...
*/
String username = request.getParameter("username");
// ...
// 获取所有的兴趣爱好
// 这个方法适合取checkbox中的数据
String[] interests = request.getParameterValues("interest");
for(String in : interesets){
System.out.println(in);
}
// 获取整个参数Map集合
Map<String,String[]> parameterMap = request.getParameterMap();
Set<String> names = parameterMap.keySet();
for(String name : names){
String[] values = parameterMap.get(name);
System.out.println(name + "=" + value);
}
// 获取参数Map集合所有的key
Enumeration<String> keys = request.getParameterNames();
while(keys.hasMoreElements()){
String key = keys.nextElement();
System.out.println(key);
}
}
}
ServletContext是Servlet上下文对象,该接口中页有这样几个方法
ServletContext是一个怎样的范围?
? 所有用户共享的一个范围对象,我们一般把ServletContext变量命名喂:application
可见这个对象代表一个应用。一个webapp只有一个这样的对象,范围极大。
接口中常用方法(二)
String getContextpath()
获取上下文路径,webapp的根路径
String getMethod()
获取浏览器的请求方式
String getRequestURI()
获取URI
StringBuffer getRequestURL()
获取URL
String getServletPath()
获取Servlet Path (url-pattern)
String getRemoteAddr()
获取客户端IP地址
void setAttribute(String name, Object o)
向request范围中添加数据
Object getAttribute(String name)
向request范围中获取数据
void removeAttribute(String name)
向request范围中移除数据
RequestDispatcher getRequestDispatcher(String path)
获取请求转发器,让转发器对象指向某个资源
void setCharacterEncoding(String env)
Cookie[] getCookies() 【后面讲Cookie的时候讲】
HttpSession getSession() 【后面讲Session的时候讲】
public class TestRequestServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
response.setContextType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 获取上下文路径【webapp的根路径】
String contextPath = request.getContextPath(); // prj
// 获取浏览器请求方式
String method = request.getMethod();
//获取请求的URI
String uri = request.getRequestURI();// prj/testServlet
// 获取请求的URL
String url = request.getRequestURL().toString();// http://localhost:8080/prj/testServlet
// 获取Servlet Path
String serlvetPath = request.getServletPath();// testServlet
// 获取客户端IP地址
String clientIp = request.getRemoteAddr();
}
}
request 范围极小,request只能完成在同一次请求中传递数据
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>a</servlet-name>
<servlet-class>com.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>a</servlet-name>
<url-pattern>/a</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>b</servlet-name>
<servlet-class>com.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>b</servlet-name>
<url-pattern>/b</url-pattern>
</servlet-mapping>
</web-app>
public class AServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
User user = new User();
user.setUsercode("111");
user.setUsername("zhangsan");
//将User对象存储到request范围
request.setAttribute("userObj",user);
// 跳转
// 执行完AServlet之后,跳转到BServlet执行,将AServlet,BServlet放到同一个请求中
// 必须使用转发技术
// forward 【转发】
// 1.获取请求转发器对象【以下转发器指向了BServlet】
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
// 2.调用请求转发器的forward方法即可完成转发
dispatcher.forward(request,response);
// 【转发是一次请求】
// request.getRequestDispatcher("/b").forward(request,response);
}
}
关于范围对象的选择
关于项目中出现乱码问题
乱码进程出现在什么位置
数据保存过程中的乱码
数据展示过程中的乱码
最终显示到网页上的数据出现中文乱码
怎么解决
设置响应的内容类型,以及对应的字符编码方式
response.setContentType("text/html;charset=UTF-8");
HTML静态页面中文乱码
<meta context="text/html;charset=UTF-8">
数据传递过程中的乱码
将数据从浏览器发送到服务器的时候,服务器接收到的是乱码
浏览器是这样发送数据给服务器的:dname=%E5%E5%E5%E5%E5%E5%E5
“市场部”对应的 ISO-8859-1 的编码:%E5%E5%E5%E5%E5%E5%E5
ISO-8859-1 是国际标准码,不支持中文编码,兼容ASCII码,又被称为 latin1 编码
不管是哪个国家的文字,在浏览器发送个服务器的时候,都会采用 ISO-8859-1 的编码方式发送
发送给web服务器之后,web服务器不知道这些数据之前是什么类型的文字(中文?日文?英文???)
所以web服务器接收到的数据出现乱码
解决数据传递过程中的乱码
万能方式,既能够解决POST请求乱码,又能解决GET请求乱码
第二种解决方式,调用 request的 setCharaterEncoding方法,但是这种方式只适合POST请求,只对请求体编码
requset.setCharacterEncoding("UTF-8");
告诉Tomcat服务器请求体中的数据使用 UTF-8 编码
第三种解决方案:专门解决GET请求的乱码问题,因为这种方式只对请求行编码
修改 CATALINA_HOME/conf/server.xml
文件,添加URIEncoding
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"/>
Connector标签种都可以编写哪些属性呢?
帮助文档:CATALINA_HOMT\webapps\docs\config\http.html
public class AServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
// String value = request.getParameter(name);//从表单上获取数据
// Object obj = request.getAttribute(name); //从request范围中获取数据(之前一定调用过setAttribute,否则为null)
String dname = request.getParameter("dname");
System.out.println(dname);// 乱码
// 第一种解决方式: 万能解决方案,post和get都可以使用
byte[] bytes = dname.getBytes("ISO-8859-1"); // 解码
dname = new String(bytes,"UTF-8"); // 编码
System.out.println(dname); // 正常
// ------------------------------------------------------
// 第二种解决方式:调用 request的 setCharaterEncoding方法,但是这种方式只适合POST请求
// 告诉Tomcat服务器请求体中的数据使用 UTF-8 编码
requset.setCharacterEncoding("UTF-8");
String dname = request.getParameter("dname");
System.out.println(dname); // 正常
}
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
String dname = request.getParameter("dname");
// 第一种解决方式: 万能解决方案,post和get都可以使用
byte[] bytes = dname.getBytes("ISO-8859-1"); // 解码
dname = new String(bytes,"UTF-8"); // 编码
System.out.println(dname); // 正常
}
}
Servlet是单实例多线程环境下运行的
什么时候存在线程安全问题
在JVM中,哪些数据可能会存在线程安全问题?
线程安全问题不止是体现在JVM中,还有可能发生在数据库中。例如多个线程共享一张表,并且同时区修改表中的一些记录,那么这些记录就会存在线程安全问题。解决方案:
怎么解决线程安全问题
Servlet怎么解决线程安全问题
关于Web系统中资源跳转
包括两种方式
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>a</servlet-name>
<servlet-class>com.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>a</servlet-name>
<url-pattern>/a</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>b</servlet-name>
<servlet-class>com.servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>b</servlet-name>
<url-pattern>/b</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>c</servlet-name>
<servlet-class>com.servlet.CServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>c</servlet-name>
<url-pattern>/c</url-pattern>
</servlet-mapping>
</web-app>
public class AServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
// 向request范围中存储数据
request.setAttribute("username","zhangsan");
// 转发 forward:一次请求
request.getRequestDispatcher("/b").forward(request,response);
}
}
public class BServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
// 从request范围中获取数据
Object obj = request.getAttribute("username");
System.out.println(obj); // zhangsan
// 重定向 redirect:两次请求
// 执行到此次之后,将这个路径响应给浏览器,浏览器又向服务器发送了一次全新的请求
//response.sendRedirect("/prj/c");
response.sendRedirect(request.getContextPath() + "/c");
}
}
public class CServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
// 从request范围中获取数据
Object obj = request.getAttribute("username");
System.out.println(obj); // null
}
}
转发和重定向代码
request.getRequestDispatcher("/b").forward(request,response);
response.sendRedirect(request.getContextPath() + "/c");
转发和重定向的区别
跳转的下一个资源可以是什么
可以是web服务器中的任一资源:可以是Servlet,也可以是HTML,JSP,...
什么时候采用转发,什么时候采用重定向 【大部分情况下都使用重定向】
重定向原理是什么
response.sendRedirect("/jd/login");
程序执行到以上代码,将请求路径 /jd/login反馈给浏览器,浏览器自动又向web服务器发送了一次全新的请求:/jd/login
,浏览器地址栏上最终显示的地址是 /jd/login
在浏览器上点击一个超链接,到最终网页停下来时一次请求。这句话不正确,因为有重定向机制存在,这个过程可能时多个请求
浏览器刷新的是最后一次请求,如果是使用转发跳转,刷新的话会重复添加数据;使用重定向则不会出现重复添加数据的问题。
public class AServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest requets, HttpServletResponse response) throws ServletException,IOException{
//
request.setRequestEncoding("UTF-8");
// 获取表单提交的用户数据
String usercode = requst.getParameter("1234");
String username = requst.getParameter("username");
// JDBC 保存信息
// xxx...
if(count == 1){
// 保存成功,“跳转”到成功页面
// 转发
// request.getRequestDispatcher("/success.html").forward(request,response);
// 重定向
response.sendRedirect(request.getContextPath + "/success.html")
}
}
}
Cookie是什么,有什么作用,保存在哪里
可以保存会话状态,但是着会话状态是保留在客户端上的
只要Cookie清除,或者Cookie失效,这个会话状态就没有了
Cookie 是保存在浏览器客户端上的
Cookie 可以保存在浏览器的缓存中,浏览器关闭Cookie消失
Cookie也可以保存在客户端的硬盘文件中,浏览器关闭Cookie还在,除非Cookie失效
Cookie只有在javaweb中有吗
Cookie实现的功能,常见的有哪些?
在Java中,Cllike被当作类来处理,使用 new运算符可以创建Cookie对象,而且Cookie由两部分组成,分别是Cookie的name和value, name和value都是 字符串类型String
在 Java程序中怎么创建 Cookie
Cookie cookie = new Cookie(String cookieName, String cookieValue);
服务器可以一次向浏览器发送多个Cookie
默认情况下,服务器发送Cookie给浏览器之后,浏览器将Cookie保存在缓存当中,只要不关闭浏览器,Cookie永远存在,并且有效。当浏览器关闭之后,缓存中的Cookie将被清除
在浏览器客户端无论是硬盘文件中还是缓存中保存的Cookie,什么时候会再次发送给服务器呢
默认情况下(没有设置 Cookie的关联路径)Cookie会和哪些路径绑定在一起?
/prj/test/createAndSendCookieToBrowser
请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端
这个浏览器中的Cookie会默认和 test/
这个路径绑定在一起
也就是说,以后只要发送 test/
请求(test/*
),Cookie一定会提交给服务器。test
请求则不会发送Cookie。
/prj/a
请求服务器,服务器生成Cookie,并将Cookie发送给浏览器客户端
这个浏览器中的Cookie会默认和 prj/
这个路径绑定在一起
public class CreateAndSendCookieToBrowserServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 创建Cookie对象
Cookie cookie1 = new Cookie("username","zhangsan");
Cookie cookie2 = new Cookie("password","123");
// 设置 Cookie的关联路径
cookie1.setPath(request.getContextPath() + "/king");
cookie2.setPath(request.getContextPath() + "/king");
// 设置 Cookie 有效期(秒)
cookie1.setMaxAge(60 * 60);
cookie2.setMaxAge(60 * 60 * 24);
// 将Cookie对象发送给浏览器客户端
response.addCookie(cookie1);
response.addCookie(cookie2);
}
}
其实路径是可以制定的,可以通过 Java程序进行设置,保证Cookie和某个特定的路径绑定在一起。
假设执行了 cookie.setPath("/prj/king");
那么 Cookie将和 “prj/king" 路径绑定在一起
只有发送 ”prj/king" 下的请求路径,浏览器才会提交Cookie给服务器
默认情况下,没有设置Cookie的有效时长,该Cookie被默认保存到浏览器的缓存当中,只要浏览器不关闭,Cookie存在;只要浏览器关闭,Cookie就消失。我们可以通过设置Cookie有效时长,以保证Cookie保存到硬盘文件当中。但是这个有效时长必须是 > 0 的。有效时长过去之后,硬盘中保存的Cookie会失效。
cookie 有效时长 = 0 直接被删除
cookie 有效时长 < 0 不会被存储
cookie 有效时长 > 0 存储到硬盘文件中
cookie1.setMaxAge(60 * 60);
一小时有效
浏览器提交Cookie给服务器,服务器怎么接收
public class ReceiveCookieServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 从 request 对象中获取所有提交的Cookie
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
System.out.println(cookieName + "=" + cookeValue);
}
}
}
}
浏览器可以禁用Cookie, 什么意思
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 欢迎页面Servlet验证是否登陆 -->
<welcome-file-list>
<welcome-file>isLogin</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>isLogin</servlet-name>
<servlet-class>com.servlet.CheckLoginStatusServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>isLogin</servlet-name>
<url-pattern>/isLogin</url-pattern>
</servlet-mapping>
</web-app>
public class LoginServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// ------------------------------
// 数据库验证账号密码操作,此处省略...
// ------------------------------
if(loginSuccess){
// 登陆成功之后,获取用户是否选择了十天内免登陆
String tenDayAutoLoginFlag = request.getParameter("tenDayAutoLoginFlag");
if("ok".equals(tenDayAutoLoginFlag)){
// 创建Cookie对象
Cookie cookie1 = new Cookie("username",username);
Cookie cookie2 = new Cookie("password",password);
// 设置有效时间
cookie1.setMaxAge(60*60*24*10);
cookie2.setMaxAge(60*60*24*10);
// 设置关联路径
cookie1.setPath(request.getContextPath());
cookie2.setPath(request.getContextPath());
// 发送 Cookie给浏览器
response.addCookie(cookie1);
response.addCookie(cookie2);
}
}
// ------------------------------
// 登陆成功或失败后的页面跳转,此处省略...
// ------------------------------
}
}
在欢迎页面获取Cookie,并进行验证,验证成功就不需要跳转到登陆页面了
public class CheckLoginStatusServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// 从request中获取所有的Cookie
Cookie[] cookies = request.getCookies();
String username = null;
String password = null;
if(cookies != null){
// 遍历Cookie
for(Cookie cookie : cookies){
String cookieName = cookie.getName();
String cookieValue = cookie.getValue();
if("username".equals(cookieName)){
username = cookieValue;
}else if("password".equals(cookieName)){
password = cookieValue;
}
}
}
if(username != null && password != null){
// ------------------------------
// 连接数据库验证账号密码操作,此处省略...
// ------------------------------
// 登陆成功则跳转到成功页面
// 登陆失败则跳转到失败页面
}else {
// 跳转到登陆页面
response.sendRedirect(request.getContextPath() + "login.html");
}
}
关于url-pattern的编写方式和路径的总结
路径的编写形式
<a href="/项目名称/资源路径"></a>
<form action="/项目名/资源路径"></form>
重定向:response.sendRedirect("/项目名/资源路径");
转发:request.getReqeustDispatcher("/资源路径").forward(request,response);
欢迎页面
<welcome-file-list>
<welcome-file>资源路径</welcome-file>
</welcome-file-list>
servlet路径
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/资源路径</url-pattern>
</servlet-mapping>
Cookie设置path
cookie.setPath("/项目名/资源路径");
ServletContext applicattion = config.getServletContext();
application.getRealPath("/WEB-INF/classes/db.properties");
//application.getRealPath("/资源路径");
url-pattern 可以编写多个
精确匹配
<url-pattern>/hello</url-pattern>
<url-pattern>/system/hello</url-pattern>
扩展匹配
<url-pattern>/abc/*</url-pattern>
后缀匹配
<url-pattern>*.action</url-pattern>
<url-pattern>*.do</url-pattern>
全部匹配
<url-pattern>/*</url-pattern>
javax.servlet.http.HttpSession
简称 session/会话public class AccessMyselfSessionServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequset request, HttpServletResponse response) throws ServletException, IOException{
String ip = request.getRemoteAddr();
HttpSession session = request.getSession();
System.out.println(ip + " s session = "+session);
// 打印:192.16.8.6.92 s session = org.apache.catalina.session.StandardSessionFacade@52e7ad
// 同一个浏览器访问多次刷新,打印内容一样
// 换一个用户访问
// 打印:192.16.8.6.30 s session = org.apache.catalina.session.StandardSessionFacade@d608f6
// 向session中存放数据
session.setAttribute("username","zhangsan");
}
}
HttpSession 对象是一个会话级别的对象,一次会话对应一个HttpSession对象
什么是一次会话?
目前可以这样理解:用户打开浏览器,在浏览器上发送多次请求,知道最终关闭浏览器,表示一次完整的会话【58节重新理解什么是一次会话】
在会话进行过程中,web服务器一直为当前这个用户维护着一个会话对象/HttpSession
在web容器中,web容器维护了大量的HttpSession对象,换句话说,在web容器中应该有一个Session列表
思考:为什么当前会话中的每一次请求可以获取到属于自己的会话对象?
思考:为什么当前会话中的每一次请求可以获取到属于自己的会话对象?(每个不同的用户对应不同的会话对象,并且不会出错)Session的实现原理?
和HttpSession对象关联的这个 Cookie的 name是比较特殊的,在Java中就叫做:jsessionid
浏览器禁用Cookie会出现什么问题?怎么解决
浏览器禁用 Cookie,则浏览器缓存中不再保存Cookie
导致在同一个会话中,无法获取到对应的会话对象
禁用Cookie之后,每一次获取的会话对象都是新的
浏览器禁用Cookie之后,若还想拿到对应的session对象,必须使用URL重写机制。怎么重写URL:
http://localhost:8080/prj/user/accessMySelfSession;jsessionid=D3D56FED7T7DS6G75S5W5D
【注意:用 ;
分隔,而不是 ?
】【使用重写URL的session即使换了浏览器或地址,访问的还是同一个会话】
重写URL会给变成带来难度/复杂度,所以一般的web站点是不建议禁用Cookie的。
浏览器关闭之后,服务器端对应的session对象会被销毁吗?为什么
session对象在什么时候会被销毁
web系统中引入了 session超时的概念
当很长一段时间(这个时间可以配置)没有用户再访问该对象,此时session对象超时,web服务器自动回收 session对象
可配置:web.xml文件中,默认是30分钟
<!-- 配置session超时时间2小时 -->
<session-config>
<session-timeout>120</session-timeout>
</session-config>
什么是一次会话
关于 javax.servlet.http.HttpSession
接口中常用的方法
ServletContext, HttpSession, HttpServletRequest 接口的对比
以上都是范围对象
ServletContext application:应用范围
HttpSession session:会话范围
HttpServletRequest request:请求范围
三个范围的排序:
application > session > request
application 完成跨会话共享数据;
session完成跨请求共享数据,但是这些请求必须在同一个会话中;
request完成跨Servlet共享数据,但是这些Servlet必须在同一个请求当中
使用原则:由小到大尝试,优先使用小范围
例如:登陆成功之后,已经登录的的状态需要保存起来,可以将登陆成功的这个状态保存到session对象中。
/**
* HttpServletRequest中获取session方法:
* public HttpSession getSession();
* 获取session,如果没获取到,新建一个session对象返回
*
* public HttpSession getSession(boolean create);
* 获取session,如果没获取到,根据create判断是否新建一个session返回
*/
public class LoginServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequset request, HttpServletResponse response) throws ServletException, IOException{
// 获取session对象,若没用获取到session对象,则新建session对象
//HttpSession session = requets.getSession();
// 获取session对象,若没用获取到session对象,则新建session对象
//HttpSession session = request.getSession(true);
// 获取session对象,若没用获取到session对象,则返回null
HttpSession session = request.getSession(false);
if(session != null){
// 销毁 session
session.invalidate();
}
}
}
原文:https://www.cnblogs.com/codeclock/p/12908751.html