Servlet

(1)Servlet与Tomcat的关系

图略

(2)概念

不能独立运行,要依赖于Web容器的一种Java服务器程序。

(3)Servlet开发的三种方式

需求:
1.进行Servlet开发,tomcat服务器向客户端发送信息。
步骤:
1.创建web应用。
2.将Servlet部署到web.xml

1. 实现Servlet接口
public class FirstServlet implements Servlet
{   //该函数用于Servlet初始化,并将其装载内存中
    //该函数只运行一次,需要在server.xml文件中进行配置<load-on-start>.
    public void init(ServletConfig config)throws ServletException
    {   }
    //得到ServletConfig对象
    public ServletConfig getServletConfig()
    {   }
    //该函数是服务函数,业务逻辑代码就是在这里编写
    //每次启动服务都会调用该函数
    //当调用doGet或者doPost才构造ServletRequest和ServletResponse对象
    public void service(ServletRequest req,ServletResponse res)
throws ServletException,java.io.IOException
    {   }
    //获取Servlet的配置信息
    public java.lang.String getServletInfo()
    {   }
    //该函数用于销毁Servlet
    //只运行一次
    public void destroy(){  }
}
2. 继承GenericServlet

相对于Servlet来说,是需要继承server函数即可。

GenericServlet抽象类,给出了一些设计servlet的一些骨架,定义了servlet的生命周期,还有一些得到的名字,配置初始化参数的方法,其设计是和应用层协议无关的。

3. 继承HttpServlet(常用)
public class FirstHttpServlet extends HttpServlet
{
    //两个底层都代用了server函数
    //Http协议中的get请求和post请求
    //与<form action="提交给?" method="get ro post?"/>中有关
    protected void doGet(HttpServletRequest req,HttpServletResonse resp)
        throws ServletException,java.io.IOException
    {
        resp.getWriter().println("HttpServlet");
    }
    protected void doPost(HttpServletRequest req,HttpServletResonse resp)
        throws ServletException,java.io.IOException
    {
        resp.getWriter().println("HttpServlet");
    }
}

(4)Servlet细节

1. Servlet的部署
<!—进行servlet的注册-->
<!-在android开发中的每个Activity都必须要注册—>
<servlet>
    <!--servlet-name 可以自定义,但是默认为类名-->
    <servlet-name>MyServlet</servlet-name>
    <!--servlet-class 用于指定servlet存放在哪一个包中(包名+类名),一定要明确-->
    <servlet-class>name.liushiyao.myservlet.MyServlet</servlet-class>
</servlet>

<!-- servlet 的映射(对一个已经注册的Servlet的映射)-->
<!--一个注册号的Servlet可以被多次映射-->
<servlet-mapping>
    <!-- 该servlet-name 一定要去上面的servlet-name 相同-->
    <servlet-name>MyServlet</servlet-name>
    <!--url 的资源文件名(斜杠必须有)-->
    <url-pattern>/ab</url-pattern>
</servlet-mapping>

注:
1. 如果url中没有加“/”运行时会出现错误。
2.在IDEA中(应该是JavaEE6的新特性,使用了annotation),可以使用@WebServlet(name = “LastTime”, urlPatterns ={“/LastTime”,”/LastTime2”})进行WebServlet的映射,且可以实现多对一映射,而不需要在web.xml中进行注册。

2. 通配符

    1) /*
    2) *.拓展名
            注:1)比2)优先级高。

3. 单例多线程

当Servlet被第一访问后,就被加载到内存中,以后该实例对各个请求都是用的是同一个内容。JSP也是单例模式。
servlet是多线程的,没有采用同步机制,是不安全的。同一个Servlet可以同时处理多个客户端的请求,比如同时有两个用户A和用户B登录时,会启动两个负责登录的Servlet线程,并通过触发Service方法来处理请求。在两个线程中,接收到的用户名是不同的,也就是说,多线程里的Servlet,可能其中的变量不相同。

4. servlet中的配置

需求:当我们的网站启动的时候,可能会要求初始化一些数据(创建临时表),或者要求定时备份数据,发送邮件。
解决办法:可以通过<load-on-startup>配合,线程知识搞定。
    通过配置<load-on-startup>,启动一个servlet中的init函数,且只运行一次。

在web.xml文件中进行配置

<!-- 配置init启动的优先级(必须配置,否者init()不会执行) -->
<load-on-startup>1</load-on-startup>
<!—数值代表启动的顺序-->

【模拟定时发送电子邮件】

//用于发送电子邮件的线程
public class Send extends Thread
{
    @Override
    public void run() {
        int count = 0;
        while(true)
        {
            try {
                //====每隔10s发送电子邮件
                Thread.sleep(10*1000);
                System.out.println("第"+(++count)+"份邮件被发送");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//使用init函数进行线程的启动
public void init() throws ServletException {
        // Put your code here
        System.out.println("ServletInit 的init函数运行。。。");
        Send send = new Send();
        send.start();
}

ServletConfig对象

1. 用途
    用于读取Servlet的一些配置信息。

在web.xml文件中。

<!-- 使用UTF-8编码 -->
<!-- 局部servlet有效 -->
<init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
</init-param>

注:String contextString = this.getServletConfig.getInitParameter(“encoding”);
要使被所有的servlet读取,应该在之外定义:

<!—所有servlet有效 -->
<context-param>
    <param-name></param-name>
    <param-value></param-value>
</context-param>

注:通过String contextString = this.getServletContext().getInitParameter(“encode”);获取
因为该属性属于全局变量,而ServletContext也是属性全局的,所以要通过getServletContext获取,而不是通过getServletConfig获取。

【获取ServletConfig中的数据】
1. 获取单一的数据在Servlet中

response.setContentType("text/html;charset=utf-8");//默认编码
PrintWriter printWriter = response.getWriter();
//获取param参数内容
String encodingString  = this.getServletConfig().getInitParameter("encoding");
request.setCharacterEncoding(encodingString);
printWriter.println(encodingString);
printWriter.close();
  1. 获取所有的数据
//获取所有的param的enum对象
Enumeration<String> enum1 = this.getServletConfig().getInitParameterNames();
while (enum1.hasMoreElements()) {
    String string = (String) enum1.nextElement();
    System.out.println(string);
    System.out.println(this.getServletConfig().getInitParameter(string));
}

HttpResponse对象

所有的信息多会封装到response中,返回给web服务。web服务器会将response信息进行拆解,形成http相应信息,返回给浏览器。
1. getWrite();与getOutputStream()
注:一个是字符流,一个是字节流。虽然说两者可以相互转换,但是针对不同的数据针对性的使用。

两个流不能同时使用。否则会出现如下异常:
java.lang.IllegalStateException: getWriter() has already been called for this response
org.apache.catalina.connector.Response.getOutputStream(Response.java:605)
org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:197)
name.liushiyao.userlogin.Download.doGet(Download.java:37)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

注:会自动关闭IO,所以不能同时出现getWrite();getOutputStream();

2. sendRedirect();

sendRedirect( 重定向)发生在浏览器的跳转,服务器根据逻辑,发送一个状态码,告诉浏览器去重新请求那个地址。

实现界面的跳转,并可以随带字符串信息。
1. 实现跳转:

//执行调转到登录成功界面(java中其中一种跳转方式)
//"/web应用名/servlet"
response.sendRedirect("/UserLogin/MainFrame");
  1. 携带字符串信息:
response.sendRedirect("/UserLogin/MainFrame?uname="+
name+"&upassword="+password

注:url与字符串信息之间通过“?”进行连接。
不同的字符串之间通过“&”连接。
sendRedirect不能实现对象的传递。但是可以通过session传递(也不能说是“传递”,只是在服务器内存中存储的session)。

User u = new User(name,password);
request.getSession().setAttribute("u",u);
  1. 获取对象:
    User us = (User)request.getSession().getAttribute("u");
    out.println(us.getName()+"||"+us.getPassword());

HttpRequest对象

该对象表示浏览器的请求,即http请求信息。但web服务器等到该请求后,会把浏览器请求的信息封装成HttpRequest对象。因此可以通过该对象获取用户的各种请求信息。
1. getRequestURL();
String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
System.out.println("uri"+uri);
System.out.println("url"+url);

输出:

uri  /RequestDemo/RequestInfo
url  http://localhost:8080/RequestDemo/RequestInfo
2. getQueryString();

以GET方法获取参数信息(参数+值)。

    String quary = request.getQueryString();
    System.out.println("query:"+quary);

输出:
query:name=123

注:这个的参数时url后面带的所有信息,而request.getParameter(“age”);则是当个属性所带的值

3. getRemoteAddr();

可以获取用户的ip地址。(利用该函数可进行ip封杀)

4. getRemotePort();

获取用户的端口。

int localport = request.getLocalPort();
int port = request.getRemotePort();
System.out.println("localport:"+localport);
System.out.println("port:"+port);
5. getParameterValues();

获得传过来的参数名相同的一个数组;
String[] string = request.getParameterValues(“checkbox”);

6. getRequestDispatcher();

request转向函数。

request.getRequestDispatcher("/MainFrame").forward(request, 
response);

实现原理:

  1. sendReDirect与forward的区别?

    forward(转向):发生在服务器的跳转,服务器请求资源,直接访问目标地址的URL,把URL的响应再发送给浏览器,浏览器根本不知道服务器发送的内容是从哪里来的,所以地址栏中的URL还是原来的。


答:(1)叫法不同:sendReDirect()叫重定向(转发);forward叫转向。
(2)实际发送的位置不同:sendReDirect发生在浏览器;forward发生在服务器
(3)用法不同:response.sendReDirect(“/web应用/资源URI”);需要加‘/web应用名’(根据其原理可以知道)
request.getRequestDispather(“/资源URI”).forward(request,response);
不需要加web应用名
(4)范围不同:sendReDirect 与浏览器之间
forward 与web服务器之间。

注:1.所谓的一次http请求:就是没有重回到浏览器或者重新启动则叫为“一次http请求”。
2.request.setAttribute(“key”,”123”);//存储此请求中的属性。在请求之间重置属性。此方法常常与 RequestDispatcher 一起使用。
3. //效果同request.getRequestDispather request.getServletContext().getRequestDispatcher(“/OtherServlet”).forward(request,response);
4. 使用sendReDirect可以防止刷新带来的再次访问servlet(因为sendReDirect需要web应用名)

1. 概念
cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器。 Cookie包含属性(String)和值(String)。

注:1. Cookie只能保存字符串(键值对)
2. 客户端在发送Http请求时,会携带该Web应用的Cookie。
3. Cookie必须设置setMaxAge,否则Cookie在浏览器关闭时被销毁(setMaxAge(0)则销毁Cookie)。
4. 可以被多个浏览器共享。
5. 如果Cookie重名,会覆盖之前的数据。
6. 当web创建多个Cookie时,会保存在同一个文件中,并且存在时间可以不一样。
7. 创建Cookie时禁止使用“ 空格、逗号”等。

2. Cookie的用途
账号和密码的保存(需要加密)、用户的喜好、设置等等。
3. Cookie的限制
一个浏览器只能存放300个Cookie,一个web站点最多存储20个Cookie,且 每个大小限制在4K。
4.禁用Cookie
如果用户禁用Cookie,可以使用URL重写技术跟踪回话。
5. Cookie的生命周期
Cookie的生命周期指的是累积时间,即从开始创建时间到设置的结束时间的长度。

Session

1. 概念
Session(域对象)是服务器端技术,当用户打开浏览器,访问服务器。服务器为每一个浏览器提供一个Session对象。 Session包含属性(String)和值(Object)。

注:1. 只要不关闭浏览器,不同的页面就会处于同一个Session中,而这个Session默认的生存时间是1800s(30分钟,可以在web.xml中修改)。
2. session是存放在服务器的内存中的
3. session被特定的一个浏览器所独享
4. 当同一个session中的属性名相同时则会覆盖前一个属性值

2. Session的生命周期
  1. 在web.xml中可以进行生存时间的设定
<session-config>
    <session-timeout>20</session-timeout>
</session-config>
  1. 使用httpSession.setMaxInactiveInterval(60);
    //该时间设置的是“发呆时间”—用户没有操作Session的时间
  2. 当关闭或重启Tomcat时都会删除Session(Session是保存在内存中的)或者使用 invalidate(); 删除Session中所有的属性和对象(强制性的,用于安全退出)
  3. 单独删除一个对象
    httpSession.removeAttribute(“name”);
3. Session的原理

服务器如何为特定的浏览器分配特定的Session?
答:通过ID
实现流程:
1. 当浏览器第一次访问Servlet时,Cookie中是没有携带JSESSIONID
(Cookie JSESSIONID=D7561FE5F83BACF4E0091BCDADE04078),
2. 访问Servlet之后,会生成Session并分配Session ID,通过Cookie写入浏览器中;
3. 当用户再次访问Servlet,http请求会携带带有JSESSIONID的cookie,此时服务器就能准确的知道该浏览器是与那个Session相关联的。

6. Cookie与Session的区别?

①存在的位置不同:
Cookie:存在客户端(临时文件夹)
Session:存在服务器的内存中(一个Session域对象为一个用户浏览器服务)
②安全性
Cookie:是以明文方式存放在客户端,安全性较弱(可以通过加密的方式进行加密)
Session:是存在服务器中的内存中,安全性较强。、
③网络通信量
Cookie:会传递信息给服务器(每次在Http请求中都会携带Cookie,所以会增加网络压力)(所以获取Cookie时是从Request中获取 的)
Session:session是存在服务器的内存中的,所以不存在网络通信压力问题。
④生命周期
Cookie:是累积时间,即为绝对时间
Session:是“发呆时间”,即相对时间(当浏览器没有对session进行操作时的间隔时间)。session失效是指无法访问session的属性(API解释:使此会话无效,然后取消对任何绑定到它的对象的绑定。)。相关应用(安全退出)
⑤访问范围
Cookie:浏览器共享
Session:浏览器独享
注:Session会占用服务器的内存,所以要根据实际情况进行取舍。

ServletContext

1. 概念
Web容器在启动时,它会为每一个Web应用程序都创建一个对应的ServletContext对象,它代表web应用。
注:可以被多个用户共享(同一个Web应用中的所有Servlet)
2. 获取ServletContext

//方法一(通过this)
ServletContext servletContext = this.getServletContext();
//方法二(通过getServletConfig)
ServletContext servletContext1 = this.getServletConfig().getServletContext();

3. 添加ServletContext属性

servletContext.setAttribute(“name”,”刘石尧”);

4. 读取ServletContext属性

String string = (String) servletContext.getAttribute(“name”);

5. 删除ServletContxt 属性

if (servletContext.getAttribute(“name”) != null){
servletContext.removeAttribute(“name”);
out.println(“已删除 name”);
}

6. 使用ServletContext的使用原则

需要数据共享,而且存储的大小不大又不想出入数据库,可以使用ServletContext。

7. ServletContext的生命周期

ServletContext是长期存放在服务器中的内存中的,所有不将过大的数据存放在ServletContext中。

8.获取web.xml中的设置参数

context.getInitParameter("param");

会话跟踪

会话跟踪是一种灵活,轻便的机制,使Web上的状态变成成为可能。
可是使用session,Cookie,地址重写和隐藏域实现。

JSP

JSP九大内置对象

内置对象 对象名称 类型 作用域
request 请求对象 javax.servlet.ServletReques Request
response 响应对象 javax.servlet.SrvletResponse Page
pageContext 页面上下文对象 javax.servlet.jsp.PageContext Page
session 会话对象 javax.servlet.http.HttpSession Session
application 应用程序对象 javax.servlet.ServletContext Application
out 输出对象 javax.servlet.jsp.JspWriter Page
config 配置对象 javax.servlet.ServletConfig Page
page 页面对象 javax.lang.Object Page
exception 例外对象 javax.lang.Throwable page

注:“exception” 对象则代表了JSP文件运行时所产生的例外对象,此对象不能在一般JSP文件中直接使用,而只能在使用了“<%@ page isErrorPage=”true “%>”的JSP文件中使用。

作用域

作用域 范围 说明
page 有效范围只在当前jsp页面里 从把变量放到pageContext开始,到jsp页面结束,你都可以使用这个变量。
request 有效范围是当前请求周期 所谓请求周期,就是指从http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个jsp页面,在这些页面里你都可以使用这个变量。
session 有效范围是当前会话 所谓当前会话,就是指从用户打开浏览器开始,到用户关闭浏览器这中间的过程。这个过程可能包含多个请求响应。也就是说,只要用户不关浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被称为一个会话(session),而放到会话中的变量,就可以在当前会话的所有请求里使用。
application 有效范围是整个应用 整个应用是指从应用启动,到应用结束。我们没有说“从服务器启动,到服务器关闭”,是因为一个服务器可能部署多个应用,当然你关闭了服务器,就会把上面所有的应用都关闭了。

  application作用域里的变量,它们的存活时间是最长的,如果不进行手工删除,它们就一直可以使用。
  

注:application里的变量可以被所有用户共用。如果用户甲的操作修改了application中的变量,用户乙访问时得到的是修改后的值。这在其他scope中都是不会发生的,page, request,session都是完全隔离的,无论如何修改都不会影响其他人的数据。

jsp注释

1. <%-- JSP中的注释,看不见 --%>
2.  // 注释,看不见
3.   /*
   注释,看不见
 */
4. <!--显式注释-->

JSP语法

脚本

<% java代码 %>:在<%%>中定义局部变量或者调用方法,但不能定义方法。

<%!%>:可以在<%!%>中声明方法、属性、全局变量。

<%=%>:称作jsp表达式,用于将已经声明的变量或者表达式输出到网页上面。

include指令

静态include:
从外部引入一个jsp文件(只含指令和内容本身,不需要body等其他内容),编译成同一个servlet。属于静态引入。

<%@ include file="B.jsp" %>

动态include:

<jsp:include />

注:动态引入,会翻译成两个servlet。所以被引入的文件可以包含等内容。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐