Servlet技术

一、JavaWeb概述

1. 什么是Javaweb

JavaWeb是指所有通过Java语言编写,可以通过浏览器访问的程序的总称。

JavaWeb是基于请求和响应来开发的。

请求:Request

响应:Response

客户端(浏览器) 服务器(Tomcat等)

2. Web资源分类

  • 静态资源:HTML,CSS,JS,txt,mp4,jpg等等
  • 动态资源:jsp页面,servlet程序

3. 常用Web服务器

  • Tomcat:提供对jsp和servlet的支持,是一种轻量级的JavaWeb容器
  • Jboss
  • GlassFish
  • Resin
  • WebLogic

4. Tomcat的使用

①Tomcat目录中的webapps文件夹存放部署的Web工程

②启动Tomcat,找到bin目录下的startup.bat文件。或者管理员权限下的cmd,输入startup。

③测试是否启动成功,访问本机真实地址或者(localhost:8080)

④停止Tomcat的方式:找到tomcat的bin目录下的shutdown.bat按钮

⑤如何修改Tomcat的端口号:
mysql默认3306,Tomcat默认8080
server.xml配置文件下的Connector标签,修改port属性,修改完端口号之后要重启Tomcat

⑥HTTP协议默认端口是80

部署Web工程到Tomcat服务器

Tomcat是一个服务器,供客户端访问Web工程。

  • 直接把Web工程拷贝到Tomcat的webapps下如何访问Web工程。先localhost:8080(这一步就相当于切入到webapps文件夹下)然后再加上这里面某个html文件的路径即可
image-20200608100549501.png

IDEA整合Tomcat服务器

  • 全局添加服务器
image-20200608100326929.png
  • 单个工程添加服务器

Server&Deployment

  • 配置工程输出路径
image-20200608100828701.png
  • 解决服务器控制台输出乱码
image-20200608100929905.png

二、Servlet

1. 什么是Servlet

  1. Servlet是JavaEE规范之一,规范就是接口
  2. Servlet是JavaWeb三大组件之一,三大组件分别是Servlet程序,Filter过滤器,Listener监听器
  3. Servlet是运行在服务器上的一个Java小程序它可以接收客户端发送过来的请求,并响应客户的请求。Tomcat等服务器相当于容器,里面装了许多Servlet。

2. 实现Servlet程序

  1. 编写一个类去实现Servlet接口

  2. 实现service方法,处理请求并响应请求得到数据(抽象类HttpServlet中service方法就包含了doGet,doPost,doDelete等等所有请求类型的方法

  3. 到web.xml文件中去配置Servlet程序的访问地址

    <-- servlet标签:给Tomcat配置Servlet程序-->
    <servlet>
        <-- servlet-name标签:给servlet程序起一个别名(别名一般是该servlet实现类的类名)-->
        <servlet-name>MyServletImpl</servlet-name>
        <-- 上面那个servlet的全限定类名-->
        <servlet-class>com.zt.MyServletImpl</servlet-class>
    </servlet>
    
    <-- servlet-mapping标签:给servlet程序配置一个访问地址-->
    <servlet-mapping>
        <-- 该处servlet-name标签作用是:告诉服务器,当前mapping标签配置的地址给哪个servlet程序用
        一般和上面那个一致,就表示该地址就给该servlet程序用-->
        <servlet-name>MyServletImpl</servlet-name>
        <-- url-pattern标签:用来配置访问地址
        /:"/"在服务器解析的时候,被解析为:http://ip:port/工程路径/。其中工程路径就是配置Tomcat时的Deployment中的context
        /hello:这表示http://ip:port/工程路径/hello,即该servlet程序要去访问这个地址,然后执行service方法
        -->
        <url-pattern>/hello</url-pattern>  //在开发的时候一般遵守习惯:/xxx,xxx的内容与类名有关联
    </servlet-mapping>
    

3. Servlet生命周期

  1. 执行Servlet构造方法
  2. 执行init()初始化方法
  3. 执行service()方法,每次调用Servlet都会调用该方法
  4. 执行destroy()方法

4. 通过继承HttpServlet实现Servlet程序

一般实际开发项目中,都是使用继承HttpServlet类(它实现了Servlet接口,它是个抽象类)去实现Servlet程序

①编写一个类继承HttpServlet

②根据业务需要重写doGet()doPost()等方法

③到web.xml文件中配置Servlet程序的访问地址


ServletConfig类

Servlet程序的配置类,它是某个servlet应用程序的config,不是全局的config

作用:

(1)可以获取Servlet程序的别名servlet-name

(2)获取初始化参数init-param

(3)获取ServletContext对象

ServletContext类

这是一个全局的对象,作用域为整个Web工程,可以用它去做一些全局性的配置,也可以获得全局的属性

image-20200608105748297.png
  1. ServletContex是一个接口,它表示Servlet上下文对象

  2. 一个Web工程只有一个ServletContext对象实例,相对于每个servlet程序而言

  3. ServletContext对象是一个域对象

  4. ServletContext在web工程部署的时候创建,在web工程停止的时候销毁

    存数据 取数据 删除数据
    Map put get remove
    域对象 setAttribute getAttribute removeAttribute
HttpServletRequest类(实现ServletRequest接口)
  • 作用
    每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到HttpServletRequest对象中,然后传递到service方法(doGet,doPost)中给我们使用。我们可以通过HttpServletRequest对象,获取到请求的所有信息

  • HttpServletRequest常用API

    String getContextPath():获取Web工程相对路径(Tomcat服务器中除去http://ip:port) 
    System.out.println(req.getContextPath());
    /Temp
    
    URI getRequestURI():获取请求的资源路径,相对路径,某Web工程下的路径
    System.out.println(req.getRequestURI());
    /Temp/hello
    
    URL getRequestURL():获取请求的统一资源定位符(绝对路径)
    System.out.println(req.getRequestURL());
    http://localhost:8080/Temp/hello
    
    String getRemoteHost():获取客户端的ip地址
    String getParameter():获取请求的参数
    String getParameterValues():获取请求的参数(多个值时)  可以用于获取用户输入的值,如用户名。
    String getHeader():获取请求头
    String getMethod():获取请求的方式GET或POST
    setAttribute(key,value):设置域数据
    Object getAttribute(key):获取域数据
    getRequestDispatcher("/+servlet名"):获取下一个转发对象。必须以斜杠开头
    RequestDispatcher rd = servletRequest.getRequestDispatcher("Two");
    rd.forward(servletRequest,servletResponse); //获取之后进入到下一个servlet总
    req.setCharacterEncoding("UTF-8")
    
HttpServletResponse类
  • 每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用,HttpServletResponse表示所有响应的信息。如果需要设置返回给客户端的信息,都可以通过HttpServletResponse对象来进行设置

  • 两个输出流

    1. 字节流:getOutputStream(),常用于下载(传递二进制数据)

    2. 字符流:getWriter(),常用于回传字符串(常用)

      resp.setContentType("text/html; charset=UTF-8");  //同时设置服务器和客户端的字符集为UTF-8
      PrintWriter writer = resp.getWriter();
      writer.write("Hello World");
      
请求重定向

请求重定向是指,客户端给服务器发送请求,然后服务器给客户端一个新地址,客户端转发到新地址。

resp.sendRedirect("http://www.sina.com");

注意

  1. 不能重定向到自己,否则浏览器会报错
  2. 浏览器地址会发生变化,请求次数为两次,而不是请求转发的一次
  3. 两个servlet程序不共享HttpServletRequest域中的数据,因为每个HttpServletRequest只属于一个Servlet
  4. 不能访问WEB-INF下的内容
  5. 可以访问工程外的资源

三、HTTP协议

1. GET请求

  • 请求的方式 GET
  • 请求的资源路径
  • 请求的协议版本号 HTTP/1.1
  • 请求头 key:value 组成

2. POST请求

  • 请求方式POST
  • 请求资源路径
  • 请求的协议版本号 HTTP/1.1
  • 请求头 key:value
  • 请求体:发送给服务器的数据
<常见的GET请求和POST请求>
GET请求:
①<form>标签,method=get
②<a>标签
③<link>标签引入css
④<Script>标签引入js文件
⑤<img>标签引入图片
⑥<iframe>标签引入html页面
⑦在浏览器地址栏中输入地址后敲回车
POST请求:
<form>标签,method=post
3. 常用请求头
  • Accept:表示客户端可以接收的数据类型
  • Accpet_language:表示客户端可以接收的语言类型
  • User-Agent:表示客户端浏览器的信息
  • Host:表示请求时的服务器ip和端口号
4. 响应的HTTP格式
  • 响应的协议和版本号
  • 响应状态码
  • 响应状态描述符
  • 响应头:key:value
  • 响应体 :回传给客户端的数据
5. 响应码
  • 200:表示请求成功
  • 302:表示请求重定向()
  • 404:表示请求服务器已经收到了,但是数据不存在(请求地址错误或数据不存在)
  • 500:表示服务器已经收到请求,但是服务器内部错误(代码错误)
6. MIME类型
  • 格式:大类型/小类型如:
    image/jpg video/mp4

四、监听器

  • 作用:监听某种事物的变化,回调函数,反馈给客户做一些响应的处理
  • ServletContextListener监听器

五、文件上传与下载

1. 上传

  • 导入依赖
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
  • form表单设置
<form action="http://localhost:8080/day01_2_war_exploded/photo" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    头像:<input type="file" name="image"><br/>
    <input type="submit" value="上传头像">
</form>
  • ServletFileUpload获得文件对象
// 1、判断上传的数据是否是多段数据,只有是多段数据才能解析
if(ServletFileUpload.isMultipartContent(req)){
    // 2、创建fileItemFactory工厂实现类
    FileItemFactory fileItemFactory = new DiskFileItemFactory();
    // 3、创建用于解析上传数据的工具类ServletFileUpload类
    ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
    // 4、解析数据,得到每一个FileItem
    try {
    //解析request,得到文件项
    List<FileItem> fileItems = servletFileUpload.parseRequest(req);
    for (FileItem f : fileItems){
        // 如果每个fileItem是普通表单项
        if (f.isFormField()){
            // 获得表单项的name属性值
            System.out.println(f.getFieldName());
            // 获得表单项的value值
            System.out.println(f.getString("UTF-8"));
       }
        // 否则上传的是文件
        else {
            // 获得表单中的各项input里的name属性名称以及他们的值
            System.out.println(f.getFieldName());
            // 获得文件名,因为上传的是文件,则要获取名称不能用getFiledName
            System.out.println(f.getName());
            // 保存在服务器,参数为地址
            f.write(new File("E:\\"+f.getName()));
        }
    }
    } catch (FileUploadException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2. 下载

  • form表单
<form action="http://localhost:8080/day01_2_war_exploded/download" method="get">
    用户名:<input type="text" name="username"><br/>
    密码:<input type="password" name="password"><br/>
    <input type="submit" value="下载文件">
</form>
  • 客户端
// 1、获取要下载的文件名
String downloadFileName = "picture.png";
// 2、获取读取要下载的文件内容的对象(ServletContext)
ServletContext sc = getServletContext();
// 获取要下载的文件类型
String mimeType = sc.getMimeType("/download/" + downloadFileName);
// 在回传数据之前,告诉客户端要返回的数据类型
resp.setContentType(mimeType);
// 告诉客户端收到的数据是用在直接使用(在浏览器打开)还是保存在本地
// Content-Disposition响应头,表示收到的数据怎么处理
// attachment:表示附件,表示下载使用 filename=表示指定下载的文件名
// 将文件名进行url编码,防止下载时客户端出现中文乱码
resp.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode(downloadFileName,"UTF-8"));
// 获取下载文件的输入流
InputStream resource = sc.getResourceAsStream("/download/"+downloadFileName);
// 3、获取响应的输出流,用于下载
OutputStream os = resp.getOutputStream();
// 4、读取输入流中全部的数据,复制给输出流,输出给客户端
IOUtils.copy(resource,os);

六、Cookie

1. 什么是Cookie

Cookie是服务器通知客户端保存键值对的一种技术,客户端有了cookie后,每次请求都发送给服务器,每个cookie的大小不超过4kB。cookie如果要支持中文,必须对值进行Base64编码

2. 设置Cookie

创建

// 创建cookie对象
Cookie cookie1 = new Cookie("key1", "value1"); //cookie可以一次创建多个
// 通知客户端保存cookie
resp.addCookie(cookie1);
Cookie cookie2 = new Cookie("key2", "value2"); //cookie可以一次创建多个
// 通知客户端保存cookie
resp.addCookie(cookie2);

流程

image-20200608121314714.png

获取

Cookie[] cookies = req.getCookies();
for (Cookie c : cookies)
System.out.println(c.getName() + " " + c.getValue());

修改

//覆盖cookie的value属性,类似Map,key不变。
// 创建cookie对象
Cookie cookie1 = new Cookie("key1", "newValue1"); //cookie可以一次创建多个
// 通知客户端保存cookie
resp.addCookie(cookie1);

存活时间

// 默认为-1,负数表示浏览器一关闭(即一个session结束),cookie就删除
cookie1.setMaxAge(-1);

// 0表示马上删除,都不需要等待浏览器关闭
cookie1.setMaxAge(0);

// 以秒为单位,设置1小时后删除
cookie1.setMaxAge(60*60);

有效路径

// 只有当访问的url是以下url时,才会创建cookie
cookie1.setPath("url");

3. 练习

免用户名登录

<form action="login" method="get">
    用户名:<input type="text" name="username" value="${cookie.username.value}"/><br/> //将保存的cookie显示到页面上
    密码:<input type="password" name="password" value="${cookie.password.value}"/><br/>
    <input type="submit" value="登录">
</form>
resp.setContentType("text/html; Charset=UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username.equals("abcd")&&password.equals("1234")){
    Cookie cookie = new Cookie(username,password);
    cookie.setMaxAge(60*60);
    resp.addCookie(cookie);
    resp.getWriter().write("登录成功");
}else {
    resp.getWriter().write("登录失败");
}

七、Session

1. 什么是Session

  • session是一个接口(HttpSession),它用来维护一个客户端和服务器之间关联的一种技术
  • 每个客户端都有自己的一个session会话
  • session会话中,经常用来保存用户登录之后的信息。(一个session就是客户端与服务器之间的一次会话,关闭客户端就结束一次会话)
  • cookie是保存在客户端,session保存在服务器端

2. 设置Session

创建和获取

// 创建Session会话对象
HttpSession session = req.getSession();
// 判断当前Session是否是新创建的
System.out.println(session.isNew());
// 获取Session的唯一标识id
System.out.println(session.getId());
// 取得key1的值
session.getAttribute("key1");

超时时间

超时时间指的是客户端两次请求之间的最大间隔

// 设置当前session的超时时间,以秒为单位,超过超时时间就销毁
// 默认的超时时间为:1800秒,因为Tomcat服务器的默认设置为30分钟
session.setMaxInactiveInterval(60);

3. Session和Cookie的关系

session技术,底层其实是基于cookie技术实现的

没有cookie的时候,getSession()获得一个session,把session的id给cookie的value。以后有了cookie,再getSession()时就获得session的id与cookie的value值相同的session。

image-20200608123228273.png

八、过滤器

1. 概述

  • 用于拦截请求,过滤响应,拦截请求的常见应用场景:权限检查、日记操作、事务操作等
  • 要求:在web工程下新建一个admin目录,目录下的所有资源必须是用于登录之后才允许访问
  • 思路:用户登录后的信息保存在服务器的session域中,检查session域中是否包含有用于登录的信息即可

Filter的生命周期

  1. 构造器方法
  2. init初始化方法
  3. doFilter过滤方法
  4. destroy销毁方法

实现filter接口,运行doFilter方法

HttpSession session = ((HttpServletRequest) request).getSession();
Object user = session.getAttribute("user");
if (user==null){
    // 如果user=null,则权限检查没有通过,就转到登录页面
    request.getRequestDispatcher("/login.jsp").forward(request,response);
}else {
    // 权限检查通过,放行,让客户端访问目标资源
    chain.doFilter(request,response);
}

Session域保存用户数据

resp.setContentType("text/html; charset=UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");

if (username.equals("abcd")&&password.equals("1234")){
    req.getSession().setAttribute("user",username);
    System.out.println(username);
    resp.getWriter().write("登录成功");
}else {
    req.getRequestDispatcher("/login.jsp").forward(req,resp);
}

web.xml配置过滤器

<!--filter标签配置一个filter过滤器-->
<filter>
    <!--给filter起一个别名-->
    <filter-name>MyFilter</filter-name>
    <!--配置filter的全限定类名-->
    <filter-class>com.zt.MyFilter</filter-class>
</filter>
<!--filter-mapping配置filter过滤器的拦截路径-->
<filter-mapping>
    <!--filter-name表示当前的拦截路径给哪个filter使用-->
    <filter-name>MyFilter</filter-name>
    <!--/斜杠表示当前的请求地址为:http://ip:port/工程路径/ 映射到idea的webapp目录下
    /admin/*表示拦截访问路径为admin目录下的全部url-->
    <url-pattern>/admin/*</url-pattern>
</filter-mapping>

2. FilterConfig类

  • 它是filter过滤器的配置文件类,Tomcat每次创建Filter的时候也会创建一个FilterConfig类的对象,包含了Filter配置文件的配置信息。作用是获取filter过滤器的配置内容
  • 过滤链FilterChain
    FilterChain.doFilter()方法的作用:
    ①如果有filter,执行下一个Filter过滤器
    ②执行目标资源(没有Filter过滤器)
  • **多级Filter执行顺序


    image-20200608125441552.png

3. Filter的拦截路径

  1. 精确匹配

    <url-pattern>/admin/demo1.jsp</url-pattern>
    
  2. 目录匹配

    <url-pattern>/admin/*</url-pattern>
    
  3. 后缀名匹配

    <表示以.html结尾的都被拦截,这个后缀名不是说必须这种文件,而是所有字符串都可以,只要有这种字符串,都会被拦截
    filter过滤器只关心请求的地址是否匹配,不关心请求的地址是否存在。>
    <url-pattern>*.html</url-pattern>
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350