当前位置: 首页 > news >正文

Servlet

介绍

Servlet是sun公司提供的一门用于开发动态web资源的技术。
Servlet是JavaWeb的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:
接收请求数据;

【1.获取信息】
处理请求;

【2.调用方法】Dao中的方法

完成响应
【3.页面跳转】
  例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。

使用

Sun公司在其API中提供了一个servlet接口,用户若想要开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:

1. 编写一个Java类,实现servlet接口。然后把开发好的Java类部署到web服务器中。

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.
PrintWriter out = response.getWriter();//获取打印流对象
out.println("hello_Servlet");//向浏览器打印数据
out.flush();//刷新
out.close();//关流
}

 2.servlet需要进行注册(在web.xml中)(手动部署)

<servlet>
        <servlet-name>Servlet1</servlet-name>
        <servlet-class>com.zym.servlet.Servlet1</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name> Servlet1</servlet-name>
        <url-pattern>/Servlet1</url-pattern>
    </servlet-mapping>

还可以直接在生成的servlet文件中配置

package com.zym.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "Servlet2",urlPatterns = "/Servlet2")
public class Servlet2 extends HttpServlet {


    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("start.............");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

Servlet的编写及配置

URL-Pattern的三种配置方式

1、完全路径匹配 以/开始 不能包含统配符* 例如: /hello /init
2、目录匹配 以/开始, /*结尾 例如: /* /aa/* /aaa/bbb/*
3、扩展名匹配 不能以/开始,以*开始 例如: *.do *.action

 

优先级

优先级:完全匹配 > 目录匹配 > 扩展名匹配 

example

Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do
当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
    Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
    Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
    Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
    Servlet引擎将调用Servlet2.
当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
    Servlet引擎将调用Servlet2。

编写注意事项

Servlet初始化时覆盖init() ,无需覆盖init(config)
根据Http请求的方式,覆盖相应的doGet或者doPost方法,无需覆盖Service方法
当doGet和doPost代码逻辑相同时,可以相互调用,简化编程

Servlet的执行过程

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。
装载并创建该Servlet的一个实例对象。
调用Servlet实例对象的init()方法。
创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

Servlet线程安全

当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。

解决方法:

1把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)

2建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。

ServletConfig对象和ServletContext对象(了解)

ServletConfig

在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。

当servlet配置了初始化参数后,通过ServletConfig对象得到初始化信息,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。

<servlet>
    <servlet-name>ConfigDemo</servlet-name>
    <servlet-class>gz.itcast.f_config.ConfigDemo</servlet-class>
    <!-- 初始参数: 这些参数会在加载web应用的时候,封装到ServletConfig   对象中 -->
    <init-param>
        <param-name>path</param-name>
        <param-value>e:/b.txt</param-value>
    </init-param>
  </servlet>

在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)
 在哪个servlet里面配置的初始化参数,只能在该servlet里面获取

servletConfig对象获取

ServletConfig config=this.getServletConfig(); 

Servlet初始化参数

//获取servletConfig对象
    ServletConfig config = this.getServletConfig();
//得到初始化值
    String name = config.getInitParameter("name");
    String age = config.getInitParameter("age");
    String address = config.getInitParameter("address");
    System.out.println(name+"   "+age+"   "+address);

ServletContext

WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletContext代表是一个web应用的环境(上下文)对象,ServletContext对象 内部封装是该web应用的信息,ServletContext对象一个web应用只有一个
一个web项目只会有一个ServletContext对象
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
对象获取方法
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。

了解ServletContext对象的功能

web.xml中配置初始化参数
    <context - param>
    <param -name>driver</param - name>
    <param -value>com.mysql.jdbc.Driver</param - value>
    </context - param>
通过context对象获得参数
    获取servletContext对象
    ServletContext context = getServletContext();
    获取初始化参数
    String initParameter = context.getInitParameter("driver");
    System.out.println(initParameter);

context.getRealPath(“路径”) //得到web应用中的资源文件
context.getResourceAsStream("路径");

 

servletContext对象获取

1)ServletContext servletContext = config.getServletContext();
2)ServletContext servletContext = this.getServletContext();

HttpServletRequest(重点)

Request获取客户端请求信息

getRequestURL方法返回客户端发出请求完整URL
getRequestURI方法返回请求行中的资源名部分
getQueryString 方法返回请求行中的参数部分
getRemoteAddr方法返回发出请求的客户机的IP地址
getMethod得到客户机请求方式
getContextPath 获得工程虚拟目录名称

Request获取请求头

获得客户机请求头
    getHeader(name)方法 --- String 
    getHeaders(String name)方法 --- Enumeration<String>
    getHeaderNames方法 --- Enumeration<String>
获得具体类型客户机请求头
    getIntHead(name)方法  --- int
    getDateHead(name)方法 --- long(日期对应毫秒)

Request获取请求参数

getParameter(name) --- String 通过name获得值
getParameterValues  --- String[ ] 通过name获得多值 checkbox
getParameterNames  --- Enumeration<String> 获得所有name
getParameterMap  --- Map<String,String[ ]> key :name value: 多值

Request请求参数乱码

POST请求乱码 :request.setCharacterEncoding("utf-8"); 
GET请求乱码 
    解决方案一:
        修改server.xml ,不建议使用此种解决方案
            <Connector port="80" protocol="HTTP/1.1" 
                       connectionTimeout="20000" 
                       redirectPort="8443" URIEncoding="utf-8"/>
    * 必须有修改tomcat服务器配置文件权限 
    解决方案二:逆向编解码
                  username = URLEncoder.encode(username, "ISO-8859-1");
                  username = URLDecoder.decode(username, "utf-8");
                  简化
                      username = new String(username.getBytes("ISO8859-1"),"utf-8");

URL特殊字符转义规则

常用转义规则
空格换成加号(+) 
+换成%2B 正斜杠(
/)分隔目录和子目录 换成%2F 问号(?)分隔URL和查询 换成%3F 百分号(%)制定特殊字符 换成%25 #号指定书签 换成%23 &号分隔参数 换成%26 java.net.URLEncoder和 java.net.URLDecoder

请求和重定向的区别

RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。 
如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于服务器的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。 
调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。
HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。 
RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。 

HttpServletResponse (重点)

Response设置响应头和状态码

状态码(Status Code)
setStatus(int)
常用状态码:200、302、304、404、500

 

头信息 (Header Info)
addHeader(String,String) 在原有值添加
setHeader(String,String) 替换原有值

Response实现页面刷新

//隔1秒之后,刷新到一个新页面
resp.setHeader("Refresh", "1;/day02/a.html");
//设置当前页面每隔1秒刷新一次
resp.setHeader("Refresh", "1");

Response实现重定向

方案1:
    resp.setStatus(304);
    resp.setHeader("Location", "/FirstWeb/aa.jsp");
方案2:
    resp.sendRedirect(“/FirstWeb/aa.jsp”); //推荐使用

Response向页面输出内容

response.getWriter().write();   发送字符实体内容
response.getOutputStream().write()  发送字节实体内容
字节流输出中文
    乱码和浏览器的编码有关
    设置浏览器默认打开的时候的编码集
    获得字节数组的时候,传入一个编码集
字符流输出中文
    response的字符流的缓冲区是ISO-8859-1编码.
    设置response缓冲区的编码.
    设置浏览器的默认打开的时候字符集编码.

Response开发细节

向客户端输出字符中文的简写方式
response.setContentType("text/html;charset=UTF-8");
字节流与字符流是互斥的
同一个页面只能使用一种流,不能同时向页面响应。
使用字符流输入数字,有可能存在问题
想输入数字时,使用字符串”1”

Response实现文件下载

设置头信息response.setHeader(“Content-Disposition”,” attachment;filename=”+文件名称);
通过response.getOutputStream()向浏览器端输出

Response禁用浏览器缓存

发送http头,控制浏览器禁止缓存当前文档内容
设置以下三个Http头信息禁用浏览器缓存
Cache-Control : no-cache
Expires: Thu, 01 Dec 1994 16:00:00 GMT (非常特殊,转换特定日期格式才可以)

Javabean【实体类】 & servlet

将jsp中java代码和html代码进行分离,将java代码写入到servlet中

servlet主要负责业务逻辑,jsp只负责显示数据

 请求->找到servlet的过程:

页面发送请求->web.xml->解析web.xml中url-pattern标签,获取值后
和请求进行匹配(equals())->获取servlet-mapping标签中的
servlet-name ->获取servlet标签中servlet-name,和mapping标签中
的name进行匹配->获取servlet-class中的值-->Class.forName("类的完整路径").newInstance()

baseServlet【加强反射】

创建一个BaseServlet继承HttpServlet【重写service方法】

这里的路径需要注意

http://localhost:8080/B/UserServlet?method=login&name=Colin&pass=123
这里的login就是方法的名字

在service方法中

package com.zym.servlet;

import javax.servlet.ServletException;
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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@WebServlet(name = "BaseServlet")
public class BaseServlet extends HttpServlet {

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String MethodName = req.getParameter("method");
System.out.println(this);
//com.zym.servlet.User_Servlet@163fc255
Class<? extends BaseServlet> clazz = this.getClass();
try {
//获取方法对象
Method method = clazz.getMethod(MethodName, HttpServletRequest.class, HttpServletResponse.class);

//执行方法
String path = (String ) method.invoke(this,req,resp);

System.out.println("路径:"+path);

if (path!=null) {
System.out.println("页面跳转");
req.getRequestDispatcher(path).forward(req,resp);
}

} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}
}
package com.zym.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "User_Servlet")
public class User_Servlet extends BaseServlet {

    public String  login(HttpServletRequest request,HttpServletResponse response){

     String name = request.getParameter("user");
        String pwd = request.getParameter("pwd");

        System.out.println(name+""+pwd);

        return "test.jsp";
    }

Cookie

Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。

Cookie会话技术的原理

服务器创建cookie对象,把会话数据存储到cookie对象中。
new Cookie("name","value");
Cookie cookieName = new Cookie("NAME","Colin")
Cookie cookiePass = new Cookie("PASS","123456")

服务器发送cookie信息到浏览器
response.addCookie(cookieName);
response.addCookie(cookiePass);

浏览器得到服务器发送的cookie,然后保存在浏览器端。

浏览器在下次访问服务器时,会带着cookie信息

服务器接收到浏览器带来的cookie信息
request.getCookies();  返回Cookie[]

核心技术点

构造Cookie对象
Cookie(java.lang.String name, java.lang.String value)

设置cookie
void setPath(java.lang.String uri)   :设置cookie的有效访问路径
void setMaxAge(int expiry) : 设置cookie的有效时间,单位是秒
void setValue(java.lang.String newValue) :设置cookie的值

发送cookie到浏览器端保存
void response.addCookie(Cookie cookie)  : 发送cookie

服务器接收cookie
Cookie[]    request.getCookies()  : 接收cookie

Cookie会话技术的使用

显示用户上次访问时间
判断用户是否是第一次访问
如果是第一次访问,需要输出欢迎,并且记录当前的时间,保存到cookie中,再回写到浏览器端。
如果不是第一次访问,获取cookie中的时间,输出时间,并且记录当前的时间,保存到cookie中,再回写到浏览器端。

Cookie细节

一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。


一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。


void setPath(java.lang.String uri) :设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。

 

Cookie数据类型只能保存非中文字符串类型的。可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

void setMaxAge(int expiry) : 设置cookie的有效时间。
正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
零:表示删除同名的cookie数据

Session

在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

Session的原理

1)第一次访问创建session对象,给session对象分配一个唯一的ID,叫JSESSIONID
2)把JSESSIONID作为Cookie的值发送给浏览器保存
3)第二次访问的时候,浏览器带着JSESSIONID的cookie访问服务器
4)服务器得到JSESSIONID,在服务器的内存中搜索是否存放对应编号的session对象。
5)如果找到对应编号的session对象,直接返回该对象
6)如果找不到对应编号的session对象,创建新的session对象,同时分配一个sessionId,然后继续走1的流程
结论:通过JSESSION的cookie值在服务器找session对象!!!!!

Session的核心技术点

创建或得到session对象
HttpSession getSession()   相当于 getSession(true)   getSession(false)
HttpSession getSession(boolean create)  

设置session对象
void setMaxInactiveInterval(int interval)  : 设置session的有效时间,设置为-1的时候表示session永远不过期;
void invalidate()     : 销毁session对象
java.lang.String getId()  : 得到session编号

保存会话数据到session对象
void setAttribute(java.lang.String name, java.lang.Object value)  : 保存数据
java.lang.Object getAttribute(java.lang.String name)  : 获取数据
void removeAttribute(java.lang.String name) : 清除数据

Session需要注意的细节

三个getSession()方法的区别
getSession(true) / getSession()  : 创建或得到session对象。没有匹配的session编号,自动创建新的session对象。
getSession(false):    得到session对象。没有匹配的session编号,返回null

Session对象销毁的时间    
    a. 默认情况30分钟服务器自动回收
    b.手动修改session回收时间,设置setMaxInactiveInterval(int interval)  (如果设置-1的话,表示永远不过期)
    c. 全局修改session有效时间,在web.xml里面设置全局的session有效时间   

Servlet的数据访问范围

application Scope  servletContext (数据库连接池,配置, 线程池, 站点访问次数) 
    每一个Web应用对应一个ServletContext
    存放所有用户都可以访问的数据
session Scope HttpSession (存放与用户相关数据) 存放每个用户自己会话过程中的数据
request Scope HttpServletRequest
(Servlet处理结果,JSP显示) 数据存放在request对象中 生成新的请求时,原request存放数据丢失

session和Cookie的区别

(1)保存位置:session-服务器,cookie--客户端
(2)保存数据不同:session存入后Object,Cookie--String
(3)运行周期:session--浏览器访问期间,Cookie可以永久保存
(4)安全性:session高于cookie

 

转载于:https://www.cnblogs.com/taozizainali/p/10997281.html

相关文章:

  • Confluence 6 配置自动备份
  • 微软云端套用新模型增加精准度 减少预测模型误差
  • 【多线程系列】AQS CAS简单介绍
  • CF1063F String Journey
  • JPA(三):JPA基本注解
  • 有哪些不用编写代码就能轻松制作生成HTML5页面的工具
  • Spring Session产生的sessionid与cookies中的sessionid不一样的问题 httpOnly 设置不起作用的问题??...
  • JS中的prototype、__proto__与constructor(图解)
  • 美丽的闭包,在js中实现函数重载
  • Android 自定义时钟控件 时针、分针、秒针的绘制这一篇就够了
  • 在树莓派2或3的kali上 RCA(a/v connector)接口的正确使用方法(多图)(原创)
  • 软件行业40岁前摸索出路,介绍小型软件项目是否可以收辛苦费?事实验证这个路子行不通...
  • Leetcode 13 罗马数字转整数
  • 012.007.android Json解析.
  • 国内开源镜像站点
  • JavaScript-如何实现克隆(clone)函数
  • Android单元测试 - 几个重要问题
  • Docker: 容器互访的三种方式
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • IDEA常用插件整理
  • JavaScript异步流程控制的前世今生
  • JS函数式编程 数组部分风格 ES6版
  • js如何打印object对象
  • Magento 1.x 中文订单打印乱码
  • MySQL QA
  • MySQL数据库运维之数据恢复
  • node学习系列之简单文件上传
  • React16时代,该用什么姿势写 React ?
  • swift基础之_对象 实例方法 对象方法。
  • VuePress 静态网站生成
  • 闭包--闭包之tab栏切换(四)
  • 后端_ThinkPHP5
  • 检测对象或数组
  • 聊聊redis的数据结构的应用
  • 使用putty远程连接linux
  • 首页查询功能的一次实现过程
  • 用mpvue开发微信小程序
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​Python 3 新特性:类型注解
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #{}和${}的区别是什么 -- java面试
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #WEB前端(HTML属性)
  • ( 10 )MySQL中的外键
  • (1)(1.11) SiK Radio v2(一)
  • (Java)【深基9.例1】选举学生会
  • (poj1.2.1)1970(筛选法模拟)
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (十)T检验-第一部分
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (四)linux文件内容查看
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统