目录
一、关于软件架构
1.软件架构分类
1.1 C/S结 构
客户端/服务器(client/server)
例如: qq、英雄联盟
优点:
速度快(大部分的数据都存储在客户端、只需要服务器传输少量的数据就行)、
用户体验好(页面美观,速度快)、
安全性高(大部分的数据是存储在客户端的,发生了地震的自然灾害,导致服务器摧毁了,但是由于大部分数据保存在客户端,影响不大)
缺点:
需要下载客户端
难维护
1.2 B/S结构
浏览器/服务器(brower/server)
例如:百度、新浪微博网页版
优点:
不需要下载客户端
容易维护
缺点:
速度慢
用户体验不好
安全性不高
1.3 B/S开发
又称为网页开发,又称为web开发
web开发分为:
web前端开发:HTML、css、js
web后端开发:c、C++、**Java**、python、php、**servlet规范**Java开发后端,又称为Java开发web,称为javaweb
二、访问网址的步骤
百度一下,你就知道 (网址)
www.baidu.com (域名)
1.步骤
打开浏览器,在浏览器输入域名
浏览器使用到域名解析器,把我们的域名解析成IP地址和端口号的方式。
通过IP地址定位到服务器,通过端口号定位到服务
2.名称解析
2.1 IP地址
-
计算机在网络中的编号,在同一个网络中,IP地址是唯一的,定位服务器。两台计算机要互相通信,首先知道对方的IP地址。
2.2 端口号
-
一个端口号就表示一个应用,比如打开MySQL就可以占用3306端口号
三、web服务器
1.浏览器
QQ浏览器、360浏览器、谷歌浏览器(推荐使用)
web服务器:tomcat(轻巧、免安装)
2.tomcat服务器的目录结构
bin目录:存放tomcat的相关的命令的
conf目录:存放tomcat配置文件
修改乱码:
lib目录:存放jar包的
logs:存放tomcat日志文件的
temp:存放临时文件的
work:存放编译后的文件的,有可能是编译后的jsp文件
webapps:存放web应用的目录的
3.tomcat关闭和开启命令
开启tomcat的指令:startup.bat
关闭tomcat的指令:shutdown.bat
四、idea集成tomcat
1.新建空的工程
-
file--->[new project] --->[empty project] --->输入以及目录--->finsh
2.在空的工程建立普通的Java模块
-
file--->[new module]--->[java]--->[模块的名称]--->finish
3.给Java添加框架支持,web
4.添加tomcat支持
5.配置tomcat环境
jdbc连接数据库的步骤: * 1.加载驱动 * 2.创建连接 * 3.编写sql语句 * 4.执行SQL语句,获取结果集 * 5.处理结果集(select 情况下) * 6.关闭流资源
6.启动tomcat
请求:浏览器向服务器发送数据。
响应:服务器向浏览器发送数据。
五、servlet的生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。
1.Servlet 遵循的过程
Servlet 初始化后调用 init () 方法。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 销毁前调用 destroy() 方法。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
2.servlet什么时候被创建
tomcat启动的时候servlet没有被创建
第一次发送对应的请求的手被创建
2.1 问题1:
2.1.1tomcat启动的时候都做了什么?
在tomcat底层其实有一个hashmap,tomcat启动的时候会扫描web.xml文件,将路径和全类名放在map中.
2.1.2 为什么不提前创建servlet?
因为如果一开始就创建所有的servlet,如果用户打开我们的项目只想做一些简单的操作,只会用到少量的servlet。
2.1.3 我们可以自己指定servlet对象是不是在tomcat启动的时候创建。
在web.xml中设置0 <load-on-startup>1</load-on-startup>
1(自然数):表示创建的顺序,数字越小越先创建'
如果有多个servlet需要启动的时候创建,数字越小,越先启动。
3.servlet什么时候被销毁
在tomcat服务器被关闭的搜被销毁
4.当我们发送请求的时候tomcat做了什么
-
获取到/test
-
回到hashmap中进行一个匹配。获取到servlet的全类名,通过反射的方式创建出对象
-
调用init方法,调用service。
-
最后关闭tomcat的时候就会销毁servlet
5.请求响应
请求:浏览器向服务器发送数据。
响应:服务器向浏览器发送数据。
原因:反射创建servlet的时候走的是无参构造方法。如果有有参构造方法就会导致默认的无参构造方法 消失。为了解决这一个问题,init方法就出现了。
5.1 init方法
/** * 做初始化的事情 * 执行的时机实在servlet被创建的时候,其实等他于构造方法。 * 做缓存的时候用。 * init方法只在servlet被创建的时候执行一次 * @param servletConfig * @throws ServletException */ @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("init方法被执行。"); }
5.2 destroy方法
/* * 这个是销毁方法,执行的时候servlet还没有被销毁 * 遗言方法。 * 也只调用一次,在tomcat服务器关闭的时候调用。 * 流资源的关闭。 * 资源的销毁。 * */ @Override public void destroy() { System.out.println("servlet即将被销毁"); System.out.println("destroy方法被执行了"); }
附五:GenericServlet
思考:在我们写的Servlet类中init方法和destory方法用的比较少,很多情况下都不用。 那我们这样直接实现Servlet接口是不是有弊端。
如何解决?
-
通过jdk8的默认方法,也许但是不好。
-
我们可以通过加一层的方式来解决这个问题。
说明继承了GenericServlet的类重写init方法是重写init的无参构造方法:
为什么重写的是这个方法? 1、我们在init方法中做的一般是初始化的操作,一比如数据库的连接,不会用到servletconfig对象 2、我们希望在其他类中也使用servletconfig这个对象。 3、在父类中带有参数的init方法有this.config = config;的操作,如果我们要重写这个方法也要把这个 补起来。 4、在父类中带有参数的init方法中会调用无参数的init方法。
六、servletConfig
1.servletconfig是由谁创建的??
-
由tomcat容器创建的
2.servletconfig是什么?
-
是servlet的配置
-
在tomcat启动的时候,扫描web.xml文件,就会把对应的信息封装到servletconfig中
3.servletconfig是不是共享的?
-
不是共享的,一个servlet对应一个servletconfig
api的讲解
七、servletContext应用域
1.servletContext对象是由谁创建的?
-
由tomcat容器创建的
2.servletContext是什么? context(环境)
-
是servlet环境
3.servletContext是所有servlet公用的还是servlet对应一个呢?
-
是所有的servlet公用的
4.servletContext的api解释
5.servletContext的生命周期
在容器启动的时候就创建
在容器关闭的时候就被销毁了
存活的时间比较长
6.servletContext又叫做应用域
-
我们可以向应用域中放一些数据,这些数据就是所有的servlet共享的
-
什么样的数据可以放在应用域中
所有servlet共享
因为servletcontext的特效就是所有的servlet共享的
数据比较小
因为servletContext存活时间很长,如果放在里面长期不用会导致空间浪费
数据不经常被修改
因为共享数据据会修改,会产生问题?
多线程情况下会导致数据不安全
7.如何向servlet应用域中存放数据
8.在实际开发中
我们都不直接实现servlet接口,也不继承GenericServlet。httpServlet,专门做HTTP协议请求和响应
servlet 爷爷
GenericServlet 父亲 实现servlet
httpServlet 儿子 继承GenericServlet
八、http协议
协议是什么?
-
双方制定的规范,如果我们都遵守这个协议,就可以达成一致
HTTP协议
-
超文本传输协议,由W3C制定的
-
超文本,图片、视频、流媒体都是超文本
1.HTTP协议中的请求协议
1.1HTTP请求协议的组成
请求行(请求方式 uri)
请求头
空白行
请求体(post才有,get没有,存放需要传送的参数数据)
1.2 get
1.3post
2.uri和utl的区别
url:统一资源定位符
http://localhost:8080/day01_war_exploded/b
uri:同一资源标识符
/day01_war_exploded/b
3.HTTP协议中的响应协议
3.1 HTTP响应协议的组成
响应行(协议版本号、状态码、响应状态)
响应头()
空白行
响应体(服务器把数据发送给浏览器)
3.2状态码
4.get请求和post请求的区别
get请求:
没有请求体,传输的数据放在地址栏上面的
对传输的数据有所限制的,只能是字符串,长度也有限制,不超过2K
get请求是期望从服务器拿到数据
get请求比较安全
get请求时有缓存的
回退:get请求是不会再次发送请求的
post请求:
有请求体,传输的数据放在请求体中的。
对数据没有限制,成都也没有限制,不单单是字符串
post请求时期望把数据传输给服务器。
post请求不太安全
post请求是没有缓存的
post请求会再次发送请求
九、HttpServlet
1.httpServlet是干什么的?
-
专门为了处理http请求的类
-
给大家演示一下具体的操作,说说直接重写doPost和doGet方法的坏处。
2.分析源码:
-
首先回顾一下servlet的生命周期
-
执行servlet的构造方法
-
通过反射执行servlet的init方法。
-
通过反射执行service方法。
-
protected void service(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
//获取发送请求的方法。
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
//如果是get请求走doGet的方法,由于子类重写了doGet方法,所以执行子类的doGet方法。
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
//如果是post请求走doPost的方法,由于子类重写了doPost方法,所以执行子类的doPost方法。
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
解释为什么不建议同时重写doGet和doPost方法。 1.如果为了避免405异常,我们可以直接重写Service的方法。 2.无法享受405异常,如果前端不按照要求来传数据,我们无法得知 3.一个类只做和这个类有关的事情。比如登录页面,就做登录的功能,那么登录我们就必须要求通过、post请求的方式来传输数据。
十、@webservlet注解
//指定servlet的名字
1. String name() default "";
@WebServlet(name = "AServlet",value = {"/abc"})
//请求路径,通过数组来接收,可以多个,如果只有value这个属性的话,就可以不写。如果只有一个地址,大括号可以不写,简化开发
2. String[] value() default {};
@WebServlet({"/aa","/bb","/cc"})
@WebServlet("/aa")
//请求路径,通过数组来接收,可以多个
3. String[] urlPatterns() default {};
@WebServlet(urlPatterns = {"/aa","/bb","/cc"})
//tomcat启动的时候是否创建servlet
4. int loadOnStartup() default -1;
@WebServlet(value = {"/abc"},loadOnStartup = 1)
//设置servlet的参数
5. WebInitParam[] initParams() default {};
@WebServlet(value = "/abc",initParams = {@WebInitParam(name = "username",value = "admin") })
十一、三种方法应用
1.Servlet接口:应用
/**
* 实现servlet接口,重写5个方法
* 在service的方法中处理请求
* 注册servlet,在web.xml中
*/
package test;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 实现servlet接口,重写5个方法
* 在service的方法中处理请求
* 注册servlet,在web.xml中
*/
public class Demo1 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//设置响应格式,设置返回到浏览器的数据类型
servletResponse.setContentType("text/html;charset=utf-8");
//获取流对象,主要是显示数据到浏览器
PrintWriter out = servletResponse.getWriter();
//在浏览器输出hello servlet
out.write("hello");
System.out.println("hello");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
<?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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>Demo1</servlet-name>
<servlet-class>test.Demo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
</web-app>
和数据库进行交互:
package servletimp;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
public class Demo2 implements Servlet {
Connection conn;
PreparedStatement pre;
ResultSet res;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/javaweb?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String name = "root";
String password = "123456";
conn = DriverManager.getConnection(url,name,password);
String sql = "select * from user";
pre = conn.prepareStatement(sql);
res = pre.executeQuery();
while (res.next()){
servletResponse.setContentType("text/html;charset=utf-8");
PrintWriter out = servletResponse.getWriter();
out.write(res.getString("id"));
out.write(res.getString("username"));
out.write(res.getString("password"));
out.write(res.getString("dept"));
out.write(res.getString("sex"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (res != null){
res.close();
}
if (pre != null){
pre.close();
}
if (conn != null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
<servlet>
<servlet-name>Demo2</servlet-name>
<servlet-class>servletimp.Demo2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo2</servlet-name>
<url-pattern>/demo2</url-pattern>
</servlet-mapping>
GenericServlet:应用
package GenericServlet;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
public class Gemo1 extends GenericServlet {
/*
重写无参的init方法,尽量不重写有参init,因为有限制,否则要加上this指向
*/
@Override
public void init() throws ServletException {
super.init();
System.out.println("重写无参的构造方法");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
servletResponse.setContentType("text/html;charset=utf-8");
//验证servletconfig能不能在service使用
ServletContext servletContext = getServletContext();
PrintWriter out = servletResponse.getWriter();
out.write("GenericServlet ");
out.write(getServletContext().toString());
}
}
<?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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>Gemo1</servlet-name>
<servlet-class>GenericServlet.Gemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Gemo1</servlet-name>
<url-pattern>/gemo1</url-pattern>
</servlet-mapping>
</web-app>
获取全局变量:
package GenericServlet;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class Gemo2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
/* 获取全局环境变量 */
ServletContext servletContext = getServletContext();
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
while (initParameterNames.hasMoreElements()){
String key = initParameterNames.nextElement();
String value = servletContext.getInitParameter(key);
PrintWriter out = servletResponse.getWriter();
out.write(key+"="+value);
System.out.println(key+"="+value);
}
}
}
<?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_4_0.xsd"
version="4.0">
<!-- 全局环境变量-->
<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>Gemo2</servlet-name>
<servlet-class>GenericServlet.Gemo2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Gemo2</servlet-name>
<url-pattern>/gemo2</url-pattern>
</servlet-mapping>
</web-app>
通过service方法设置全局变量(servletContext)
package GenericServlet;
import javax.servlet.*;
import java.io.IOException;
public class setCon extends GenericServlet {
//获取servletContext对象
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//向应用域中存放数据
ServletContext servletContext = getServletContext();
//第一个参数:标识符,第二个参数:具体存放的数据:又见map
servletContext.setAttribute("username","admin");
System.out.println("在应用域中的数据:"+servletContext.getAttribute("username"));
}
}
HttpServlet:应用
package GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet(value = "/gemo3",initParams = {@WebInitParam(name = "username",value = "admin")})
public class Gemo3 extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("Gemo3被创建了");
System.out.println(getServletConfig().getServletName());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("执行了Servlet");
Enumeration<String> initParameterNames = getServletConfig().getInitParameterNames();
while (initParameterNames.hasMoreElements()){
String key = initParameterNames.nextElement();
String value = getServletConfig().getInitParameter(key);
System.out.println(key+"="+value);
}
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
super.service(req, res);
}
}
十二、web欢迎页面
1.改变web欢迎页面
方式一:
在conf目录下web.xml文件中有配置web欢迎页面的规则
//从下往下找,全局设置,不要改
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
方式二:
在WEB-INF下的web.xml中配置,添加welcome-file-list
<!-- 配置我们的欢迎页面-->
<welcome-file-list>
<!-- 不要以“/”开头-->
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
注意:局部和全局同名时,局部生效
十三、HttpServletRequst
1.是由谁创建的?
-
是由tomcat容器创建的
2.httpServletRequest是用来做什么的?
-
是一个请求对象,使用接收HTTP请求的,浏览器向服务器传输数据,tomcat会把数据封装到Request对象中。因为我们发送的数据满足HTTP协议。
3.封装的数据结构
如果你是tomcat开发人员你会采用什么样的数据结构来封装这些数据。
-
使用map对数据进行封装,map<String,String[]>
4.如何获取request对象中的数据
//也是根据key获取value,返回的类类型是String,如果key对应的value是单个值,就获取到这个值,如果是多个值,就获取到第一个值
1.String getParameter(String var1);
//获取浏览器传过来的参数,最常用的方法
String username = request.getParameter("username");
System.out.println(username);
*********************
2.Enumeration<String> getParameterNames();
//通过key获取value,返回String类型的字符串
3.String[] getParameterValues(String var1);
String[] hobbies = request.getParameterValues("hobby");
for (String hobby:hobbies){
System.out.println(hobby);
}、
//获取存放参数的map
4.Map<String, String[]> getParameterMap();
Map<String, String[]> parameterMap = request.getParameterMap();
parameterMap.forEach((k,v)-> System.out.println(k+"="+v[0]));
*********************
5.数据格式:
map<key,value>,map<String,String[]> username=admin&password=123&hobby=xy&body=wd
面试题:补充快速异常和安全异常
问题:迭代器中删除元素,使用了list的remove方法报错
解决方法:使用迭代器的remove方法
解释:
6.request又叫请求域。
请求域中的生命周期。
一个service方法结束,请求域的生命周期就结束了。
一次请求结束,请求域的生命周期就结束了
通过向其中一个servlet的请求域中放数据,另一个servlet得不到数据,所以请求域不是全局的,一个servlet对应一个请求域。
通过内存地址可以验证
6.1往我们的请求域中添加数据api
//向请求域中存放数据
request.setAttribute("username","admin");
//获取请求域中的数据
Object username = request.getAttribute("username");
//设置返回数据的格式
response.setContentType("text/html;charset=utf-8");
//获取流对象,输出到页面上
PrintWriter out = response.getWriter();
out.write(request.toString());
//设置返回数据的格式
response.setContentType("text/html;charset=utf-8");
//获取流对象,输出到页面上
PrintWriter out = response.getWriter();
out.write(request.toString());
6.2关于request的其他api
//其他qpi
//获取虚拟地址,/day03_war_exploded
String contextPath = request.getContextPath();
System.out.println(contextPath);
//获取请求方式,GET
String method = request.getMethod();
System.out.println(method);
//获取url,url=http://localhost:8080/day03_war_exploded/c
StringBuffer requestURL = request.getRequestURL();
System.out.println("url="+requestURL);
//获取uri,urI=/day03_war_exploded/c
String requestURI = request.getRequestURI();
System.out.println("urI="+requestURI);
7.不同的servlet共享数据怎么办
-
把数据放在应用域中
-
把数据放在请求域中,通过请求转发的方式让数据共享
方式1:通过请求转发的方式让数据共享
DServlet:
@WebServlet("/d")
public class DServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//向请求域中存放数据
request.setAttribute("username","admin");
//获取请求域中的数据
String username = (String) request.getAttribute("username");
//请求转发
// 到Eservlet,让EServlet使用到DServlet的请求对象
//参数是我们想要去的地址
//和@WebServlet("/路径")是一个地址。
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/e");
//前往,把request和response传过去
requestDispatcher.forward(request,response);
}
EServlet:
@WebServlet("/e")
public class EServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = (String) request.getAttribute("username");
//设置返回数据的格式
response.setContentType("text/html;charset=utf-8");
//获取流对象,输出到页面上
PrintWriter out = response.getWriter();
if (username != null) {
out.write(username);
}
}
十四、HttpServletResponse
常用api
1.设置返回数据的格式
//
response.setContentType("text/html;charset=utf-8");
2.获取流对象
//获取流对象
PrintWriter out = response.getWriter();
3.重定向,发送重定向
//重定向,发送重定向
//参数表示我们要去往的地址,加上项目的虚拟地址
response.sendRedirect(req.getContextPath()+"/main.jsp");
十五、请求转发和重定向的区别
1.地址栏的区别:
请求转发不会导致地址栏发生变化
重定向会导致地址栏发生变化
2.实质的区别:
-
请求转发的资源跳转是在服务器之间进行资源跳转的
-
重定向的资源跳转就是在浏览器和服务器之间
3.速度区别
-
请求转发的速度比重定向的速度快
4.参数区别
-
请求转发不需要到虚拟路径
-
重定向需要虚拟路径
5.资源跳转 请求转发和重定向怎么选择
什么时候使用请求转发
如果是希望使用请求域中的数据可以选择请求转发
对速度要求比较快的情况下可以使用请求转发,情况比较少
请求转发存在的问题:
如果不消息刷新了页面,可能会导致数据重复提交
什么时候使用重定向
除了请求转发的以上两种情况外都可以使用重定向
十六、session
1.session是什么
-
session是会话
-
用户打开浏览器,发送一系列的请求。然后最后到关闭浏览器的过程,这个过程可以称为一次会话。
2.session的出现是为了解决什么问题?
-
解决保持某种状态,保存我们的登录状态。(也就是说,访问其他的页面之前需要先判断是否登录了,做个登录的记录)
-
session的出现可以解决HTTP协议无状态的问题
-
session可以看作是一个令牌,到了某个地方,就可以获取令牌。从而证明来过此地
3.HTTP协议是无状态的。
-
在发送一次请求后,浏览器和服务器的连接就断开了,服务器做的一系列的事情,浏览器都是不知道的,只有最后返回响应数据的时候,浏览器才知道做了什么。
4.HTTP协议无状态的原因
-
这个时间点,同时有100W人访问了百度。100W个请求和服务器相连,导致服务器压力大,容易崩溃。
-
减小服务器的压力
5.关于session获取的例子
@WebServlet("/s1")
public class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session的api
HttpSession session = request.getSession();
//session是多个servlet共享的吗?结论:session是多个servlet共享的
//session也是一个域对象,会话域。可以向会话域中添加数据
session.setAttribute("username","admin");
}
}
@WebServlet("/s2")
public class SessionServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session的api
HttpSession session = request.getSession();
//session是多个servlet共享的吗
//从会话域中获取数据
Object username = session.getAttribute("username");
System.out.println(username);
}
}
6.应用域和会话域的区别
会话域的生命周期比较短,是在浏览器打开到关闭的过程中(简单理解)
如果关闭浏览器再重新打开,想从应用域中获取这个数据可以获取到吗?
在应用域中可以获取到这个数据。
如果关闭浏览器再重新打开,想从会话域中获取这个数据可以获取到吗?
在会话域中不可以获取这个数据,为null
因为关闭浏览器的时候session对象被销毁了,重写打开浏览器又是新的session
运行时的地址
关闭浏览器重新打开的地址:
7.session的原理
8.做一个简易的登录拦截
目的:必须要先登录,才能进行数据添加。
9.sessio什么时候被销毁
-
浏览器关闭的时候销毁
-
如果很久不用到这个session,也会被销毁
-
如何设置session存活时间
-
在web.xml中可以或设置,单位是分钟
-
<!-- 设置session存活时间--> <session-config> <!-- 单位是分钟--> <session-timeout>60</session-timeout> </session-config>
-
-
10.总结一下写到的三个域
应用域
请求域
会话域
大小关系
请求域<会话域<应用域
用共同的api的
XX.setAttribute:向域中存放数据
XX.GetSttribute:从域中取数据
使用频率
请求域>会话域>应用域
十七、cookie
1.cookie是什么
cookie:JSESSIONID=29AEFDCF8E95EA9943B644500006A28,username=admin,password=123
2.cookie是做什么的
和session一起保存某种状态
举例:
-
cookie充当会员卡;
-
session可以看作保险柜的密码;
-
JSESSIONID对应是哪个保险柜;
-
29AEFDCF8E95EA9943B644500006A28对应的是保险柜的密码
3.如何获得cookie,如果向cookie中存数据
存入数据:
@WebServlet("/c1")
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建cookie
Cookie cookie = new Cookie("username","admin");
Cookie cookie1 = new Cookie("password","123");
//将cookie放在响应对象中
response.addCookie(cookie);
response.addCookie(cookie1);
}
}
取出数据:
@WebServlet("/c2")
public class CookieServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取cookie
Cookie[] cookies = request.getCookies();
for (Cookie cookie:cookies){
System.out.println(cookie.getName()+"="+cookie.getValue());
}
}
}
4.cookie可以保存在哪里
-
cookie可以保存在浏览器,但是浏览器关闭的时候cookie就消失
-
cookie可以保存在本地
-
如何保存在本地
-
使用setMaxAge()方法
-
//把cookie保存在本地,参数需要保存的时间,单位是秒,浏览器关闭的时候并没有销毁这个cookie‘ //参数为正数的时候 cookie.setMaxAge(60*60); //参数为负数的时候,设置负数和不设置没有区别 cookie.setMaxAge(-3600); //参数为0 的情况,为了去除同名的cookie cookie.setMaxAge(0);
-
十八、session和cookie的区别
-
1.存储位置
-
session是存储在服务器中;底层是map
-
cookie是存储在浏览器中
-
-
2.存储数据格式
-
session通过setAttibute()来存储任意数据
-
cookie是通过new Cookie()来存储数据,只能存储字符串
-
-
3.安全性
-
session的安全性比cookie高,session是存储在服务器中的。
-
-
4.存储个数
-
cookie的存储个数是有限制的,每个浏览器不一样
-
session的存储数量更多
-
十九、过滤器
1.过滤器是什么?
-
饮水机过滤器
-
空气净化器
2.servlet的过滤器
-
登录过滤器
3.如何使用过滤器
-
实现过滤器的步骤:
-
* 1.实现filter接口 * 2.重写doFilter方法 * 3.注册过滤器(@webFilter)
-
4.如何拦截请求?怎么设置拦截哪些请求
@WebFilter("/user/*")
public class AFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("A过滤器开始执行");
//做逻辑判断
//放行操作,走到下一个过滤器,如果没有过滤器就执行目标方法,就走到下一个方法
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("A过滤器执行结束");
}
}
5.过滤器有哪些过滤路径
4种情况:
1.精准匹配,只可以过滤单个路径,/a.do
@WebFilter("/a.do")
2.后缀匹配,格式: .do ,.XXX
注意前面不要加/
@WebFilter("*.do")
3.前缀匹配,格式: /user/*
@WebFilter("/user/*")
4.全部匹配:/*
@WebFilter("/*")
6.过滤器的执行顺序
1.情况1
过滤器如果采用注解的方式进行注册,就会依据字典顺序,按拼音顺序
2.情况2
在web.xml中进行注册
过滤器执行的顺序就是注册的顺序
<!--测试过滤器B-->
<filter>
<filter-name>BFilter</filter-name>
<filter-class>filter.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
<!--测试过滤器A-->
<filter>
<filter-name>AFilter</filter-name>
<filter-class>filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
6.登录拦截
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 做登录拦截
*
*什么资源进行放行?登录页面,成功登录后,发起请求的资源
*登录请求
*
*什么资源要进行拦截?其他页面,没有登录成功后发起的资源
*/
@WebFilter("/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//登录页面的地址是怎么样的?
//转换类型
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//获取uri,放行登录页面、放行登录请求
String uri = request.getRequestURI();
//逻辑 获取虚拟路径/day03_war_exploded
String contextPath = request.getContextPath();
if ( (contextPath+"/login.jsp").equals(uri)|| (contextPath+"/").equals(uri) || (contextPath+"/login").equals(uri)){
filterChain.doFilter(request,response);
return;
}
//放行 成功登录后的页面
HttpSession session = request.getSession();
String ident = (String) session.getAttribute("login");
if (ident != null){
//说明登录过了,进行放行
filterChain.doFilter(request,response);
}else {
//还未登录,跳转回登录页面
//提示请先登录
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
}
二十、监听器
1.监听器的作用
监听一些行为和事件
2.servlet中的监听器
监听某些对象是否创建,是否销毁。有没有向域中放数据
3.监听器的种类(6种)
3.1 ServletContextListener
监听servletContext对象的创建和销毁的监听器
实现监听器的步骤: * 1.实现对应的监听器接口ServletContextListener * 2.根据需要重写方法 * 3.注册监听器
@WebListener
public class ContextListener implements ServletContextListener {
//此方法监听context对象什么时候被创建
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Context对象被创建了");
}
//此方法监听context对象什么时候被销毁
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Context对象被销毁了");
}
}
3.2 HttpSessionListener
监听HttpSession对象的创建和销毁的监听器
实现监听器的步骤: * 1.实现对应的监听器接口HttpSessionListener * 2.根据需要重写方法 * 3.注册监听器
@WebListener
public class SessionLisstener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session对象被创建了");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session对象被销毁了");
}
}
4.实现监听器的步骤
1.实现具体的监听器接口
2.选择重写的方法,如sessionCreated
3.注册监听器,@WebListener
5.练习
util.MySessioncontext:存储session
package listener;
import utils.MySessionContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 监听session什么时候被创建,创建好后,放在map中,
*/
@WebListener
public class SessionListener implements HttpSessionListener {
//此方法表示监听session什么时候被创建
//把session对象放在map中
@Override
public void sessionCreated(HttpSessionEvent se) {
//获取session对象
HttpSession session = se.getSession();
//把session放入map中
//MySessionContext.getInstance();保存单例
MySessionContext instance = MySessionContext.getInstance();
instance.addSession(session);
}
}
升级案例:解决cookie被禁用的问题
二十一、mvc的设计模式
1.在经典的mvc设计模式中,三层的意义
M表示业务模型
V表示视图模型
C表示控制层
2.分层有什么好处
可以减少不同模块之间的依赖
实现代码分离,解耦合
利用排错
3.具体分层(3层)
控制层Controller
接收前端传输过来的数据
返回数据给前端
调用业务处理业务逻辑
业务层Service
处理业务逻辑*****
调用持久层,查询数据
返回数据到控制层
持久层Mapping/Dao
和数据库进行交互
把结果返回给业务层