目录
一、关于软件架构
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
和数据库进行交互
把结果返回给业务层