JavaWeb笔记(二)

四、Servlet

Servlet 为创建基于 web 的应用程序提供了基于组件、独立于平台的方法,可以不受 CGI (Common Gateway Interface,公共网关接口) 程序的性能限制。Servlet 有权限访问所有的 Java API,包括访问企业级数据库的 JDBC API。

一、servlet原理

  1. 生命周期
    1. Servlet 初始化后调用 init () 方法。
    2. Servlet 调用 service() 方法来处理客户端的请求。
    3. Servlet 销毁前调用 destroy() 方法。
    4. 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
  2. 生命周期架构
    1. 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
    2. Servlet 容器在调用 service() 方法之前加载 Servlet。
    3. 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
  3. Serlvet接口Sun公司有两个默认的实现类:HttpServlet(HttpServlet的父类)GenericServlet

只需要继承HttpServlet实现doGet、doPost方法,就可以完成一个servlet的实现过程。

public class HelloServlet extends HttpServlet {
     
    
    //由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     
        resp.getWriter().print("Hello,Serlvet");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     
        doGet(req, resp);
    }
}

二、servlet映射

servlet在web.xml中的映射主要的作用是让服务器知道客户端发送的请求被哪个servlet来进行处理响应。

<servlet>
    <servlet-name>helloservlet-name>
    <servlet-class>zak.plus.HelloServletservlet-class>
servlet>
<servlet-mapping>
    <servlet-name>helloservlet-name>
    <url-pattern>/hellourl-pattern>
servlet-mapping>
  1. 默认请求路径: /*

  2. 一个Servlet可以指定一个映射路径: /hello

  3. 一个servlet可以指定多个映射路径: /hello、/world

  4. 一个servlet可以指定通用映射路径: /hello/*

  5. 指定一些后缀或者前缀(注意点:*前面不能加项目映射的路径)

优先级指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;

三、ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用

1、共享数据

ServletContext中设置的数据可以在任何一个servlet中获取到

String username = (String) this.getServletContext().getAttribute("username");

2、获取初始化参数


<context-param>
    <param-name>urlparam-name>
    <param-value>jdbc:mysql://localhost:3306/mybatisparam-value>
context-param>
String url = this.getServletContext().getInitParameter("url");

3、请求转发

this.getServletContext().getRequestDispatcher("/gp").forward(req,resp);

4、读取资源文件

读取resources目录、java目录下的properties文件

发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath:

InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/aa.properties");
Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("username");
String pwd = prop.getProperty("password");

四、HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest 对象,一个代表响应的一个HttpServletResponse

  • 获取客户端参数:使用HttpServletRequest
  • 响应客户端信息:使用HttpServletResponse

操作servlet请求前要先设置编码及响应类型,防止乱码产生。

req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");

设置响应头信息

// 3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则有可能乱码
resp.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(fileName,"UTF-8"));
//如何让浏览器3秒自动刷新一次;
resp.setHeader("refresh","3");
//告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpeg");
//网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");

输出流

// 字节流、非文本数据输出
resp.getOutputStream();
// 字符流、文本数据输出
resp.getWriter();

重定向

resp.sendRedirect("/hello");

五、HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器, HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息

参数获取

String username = req.getParameter("username");
String[] hobbys = req.getParameterValues("hobbys");

转发

req.getRequestDispatcher("/success.jsp").forward(req,resp);

六、重定向与转发

重定向:客户端的请求在服务端会再一次生成新的请求路径进行访问,原来请求和响应都是重新生成的。

转 发:客户端的请求在服务端会将请求和响应发送给另外的servlet进行处理,将处理好的结果响应给客户端。

相同点:都是通过其他的servlet进行处理

不同点:

  1. 重定向的请求路径会发生变化
  2. 转发的请求路径不会发送变化
  3. 重定向的请求和响应都是新的
  4. 转发的请求和响应都是同一个

五、Cookie、Session

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

Cookie

Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

Cookie的不可跨域名性

Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。

Unicode编码:保存中文

中文与英文字符不同,中文属于Unicode字符,在内存中占4个字符,而英文属于ASCII字符,内存中只占2个字节。Cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会乱码。

提示:Cookie中保存中文只能编码。一般使用UTF-8编码即可。不推荐使用GBK等中文编码,因为浏览器不一定支持,而且JavaScript也不支持GBK编码。

BASE64编码:保存二进制图片

Cookie不仅可以使用ASCII字符与Unicode字符,还可以使用二进制数据。例如在Cookie中使用数字证书,提供安全度。使用二进制数据时也需要进行编码。

注意:本程序仅用于展示Cookie中可以存储二进制内容,并不实用。由于浏览器每次请求服务器都会携带Cookie,因此Cookie内容不宜过多,否则影响速度。Cookie的内容应该少而精。

设置Cookie的所有属性
//获得Cookie
Cookie[] cookies = req.getCookies(); 
//获得cookie中的key
cookie.getName(); 
//获得cookie中的vlaue
cookie.getValue(); 
//新建一个cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+""); 
//设置cookie的有效期 Cookie默认的maxAge值为–1。
cookie.setMaxAge(24*60*60); 
//响应给客户端一个cookie
resp.addCookie(cookie); 

注意:从客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name与value属性。maxAge属性只被浏览器用来判断Cookie是否过期。

Cookie的修改、删除

Cookie并不提供修改、删除操作。如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数代表其他的意义。读者可以通过上例的程序进行验证,设置不同的属性。

注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。

Cookie的域名

Cookie是不可跨域名的。域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie。

正常情况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数,例如:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setDomain(".helloweenvsfei.com"); // 设置域名
cookie.setPath("/"); // 设置路径
cookie.setMaxAge(Integer.MAX_VALUE); // 设置有效期
response.addCookie(cookie); // 输出到客户端

读者可以修改本机C:\WINDOWS\system32\drivers\etc下的hosts文件来配置多个临时域名,然后使用setCookie.jsp程序来设置跨域名Cookie验证domain属性。

注意:domain参数必须以点(".")开始。另外,name相同但domain不同的两个Cookie是两个不同的Cookie。如果想要两个域名完全不同的网站共有Cookie,可以生成两个Cookie,domain属性分别为两个域名,输出到客户端。

Cookie的路径

domain属性决定运行访问Cookie的域名,而path属性决定允许访问Cookie的路径(ContextPath)。例如,如果只允许/sessionWeb/下的程序使用Cookie,可以这么写:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setPath("/session/"); // 设置路径
response.addCookie(cookie); // 输出到客户端

设置为“/”时允许所有路径使用Cookie。path属性需要使用符号“/”结尾。name相同但domain不同的两个Cookie也是两个不同的Cookie。

注意:页面只能获取它属于的Path的Cookie。例如/session/test/a.jsp不能获取到路径为/session/abc/的Cookie。使用时一定要注意。

  1. domain表示的是cookie所在的域,默认为请求的地址,如网址为www.test.com/test/test.aspx,那么domain默认为www.test.com。而跨域访问,如域A为t1.test.com,域B为t2.test.com,那么在域A生产一个令域A和域B都能访问的cookie就要将该cookie的domain设置为.test.com;如果要在域A生产一个令域A不能访问而域B能访问的cookie就要将该cookie的domain设置为t2.test.com。
  2. path表示cookie所在的目录,默认为/,就是根目录。在同一个服务器上有目录如下:/test/,/test/cd/,/test/dd/,现设一个cookie1的path为/test/,cookie2的path为/test/cd/,那么test下的所有页面都可以访问到cookie1,而/test/和/test/dd/的子页面不能访问cookie2。这是因为cookie能让其path路径下的页面访问。
  3. 浏览器会将domain和path都相同的cookie保存在一个文件里,cookie间用*隔开。
Cookie的安全属性

HTTP协议不仅是无状态的,而且是不安全的。使用HTTP协议的数据不经过任何加密就直接在网络上传播,有被截获的可能。使用HTTP协议传输很机密的内容是一种隐患。如果不希望Cookie在HTTP等非安全协议中传输,可以设置Cookie的secure属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。下面的代码设置secure属性为true:

Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie
cookie.setSecure(true); // 设置安全属性
response.addCookie(cookie); // 输出到客户端

提示:secure属性并不能对Cookie内容加密,因而不能保证绝对的安全性。如果需要高安全性,需要在程序中对Cookie内容加密、解密,以防泄密。

JavaScript操作Cookie

Cookie是保存在浏览器端的,因此浏览器具有操作Cookie的先决条件。浏览器可以使用脚本程序如JavaScript或者VBScript等操作Cookie。这里以JavaScript为例介绍常用的Cookie操作。例如下面的代码会输出本页面所有的Cookie。

Session

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

实现用户登录
HttpSession session = request.getSession();       // 获取Session对象
session.setAttribute("loginTime", new Date());     // 设置Session中的属性

out.println("登录时间为:" +(Date)session.getAttribute("loginTime"));      // 获取Session属性

注意:各个客户端的Session是彼此独立,互不可见。

Session的生命周期

Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。

Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。

Session的有效期

由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。

Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。

Tomcat中Session的默认超时时间为20分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。可以修改web.xml改变Session的默认超时时间。例如修改为60分钟:

<session-config>
   <session-timeout>60session-timeout>      
session-config>

注意:参数的单位为分钟,而setMaxInactiveInterval(int s)单位为秒。

在server.xml中定义context时采用如下定义(单位为秒):

<Context path="/livsorder" docBase="/home/httpd/html/livsorder" defaultSessionTimeOut="3600" isWARExpanded="true"
    isWARValidated="false" isInvokerEnabled="true"
    isWorkDirPersistent="false"/>
Session的常用方法

Session中包括各种方法,使用起来要比Cookie方便得多。Session的常用方法如下所示。

void setAttribute(String attribute, Object value):设置Session属性。value参数可以为任何Java Object。通常为Java Bean。value信息不宜过大

String getAttribute(String attribute):返回Session属性,返回Session中存在的属性名

void removeAttribute(String attribute):移除Session属性

String getId():返回Session的ID。该ID由服务器自动创建,不会重复

long getCreationTime():返回Session的创建日期。返回Session的最后活跃时间。返回类型为long

int getMaxInactiveInterval():返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效 void setMaxInactiveInterval(int second):设置Session的>超时时间。单位为秒

Cookie与Session的区别

  1. cookie数据存放在客户的浏览器上,session数据放在服务器上;
  2. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session;
  3. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用cookie;
  4. 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K;

六、JSP

JSP(全称JavaServer Pages)是由[Sun Microsystems](https://baike.baidu.com/item/Sun Microsystems)公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。

一、jsp原理

JSP 本质上就是一个Servlet

jsp文件会在第一次访问的时候经过编译生成servlet来进行请求响应处理

  1. 首先会在本地的idea配置目录work下生成jsp对应的servlet文件
C:\Users\xxx\.IntelliJIdea2018.1\system\tomcat\Unnamed_java-web\work\
  1. jsp生成的servlet

    • 继承的父类

      extends org.apache.jasper.runtime.HttpJspBase
      
    • 主体方法

    // 初始化
    public void _jspInit()
    // 销毁
    public void _jspDestroy()
    // JSPService主要的调用
    public void _jspService(HttpServletRequest request,HttpServletResponse response)
    
    • 内置对象
    1、request对象

    request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

    2、response对象

    response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。

    3、session对象

    session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。

    4、application对象

    application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。

    5、out 对象

    out 对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。

    6、pageContext 对象

    pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。

    7、config 对象

    config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数。

    8、page 对象

    page 对象代表JSP本身,只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量,类似于Java编程中的 this 指针。

    9、exception 对象

    exception 对象的作用是显示异常信息,只有在包含 isErrorPage=“true” 的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。excepation对象和Java的所有对象一样,都具有系统提供的继承结构。exception 对象几乎定义了所有异常情况。在Java程序中,可以使用try/catch关键字来处理异常情况; 如果在JSP页面中出现没有捕获到的异常,就会生成 exception 对象,并把 exception 对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的 exception 对象。

二、jsp语法

jsp表达式
  <%--JSP表达式
  作用:用来将程序的输出,输出到客户端
  <%= 变量或者表达式%>
  --%>
  <%= new java.util.Date()%>
jsp脚本片段
<%--jsp脚本片段--%>
<%
    int sum = 0;
for (int i = 1; i <=100 ; i++) {
     
    sum+=i;
}
out.println("

Sum="+sum+"

"
); %> <hr> <%--在代码嵌入HTML元素--%> <%for (int i = 0; i < 5; i++) { %> <h1>Hello,World <%=i%> </h1> <%}%>
jsp声明
<%!
static {
     
    System.out.println("Loading Servlet!");
}
private int globalVar = 0;
public void kuang(){
     
    System.out.println("进入了方法Kuang!");
}
%>

JSP声明:会被编译到JSP生成Java的类中!其他的,就会被生成到_jspService方法中!

在JSP,嵌入Java代码即可!

<%%>
<%=%>
<%!%>
<%--注释--%>

jsp的注释,不会在客户端显示,HTML会!

jsp指令
<%@page args.... %>
<%@include file=""%>

<%--@include会将两个页面合二为一--%>

<%@include file="common/header.jsp"%>
<h1>网页主体</h1>

<%@include file="common/footer.jsp"%>
<hr>
<%--jSP标签
    jsp:include:拼接页面,本质还是三个
    --%>
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>
EL表达式: ${ }
  • 获取数据
  • 执行运算
  • 获取web开发的常用对象
JSTL表达式

JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和Java代码一样

JSTL标签库使用步骤
  • 引入对应的 taglib
  • 使用其中的方法
  • 在Tomcat 也需要引入 jstl的包,否则会报错:JSTL解析错误

c:if

<form action="coreif.jsp" method="get">
    <%--
    EL表达式获取表单中的数据
    ${
     param.参数名}
    --%>
    <input type="text" name="username" value="${param.username}">
    <input type="submit" value="登录">
</form>

<%--判断如果提交的用户名是管理员,则登录成功--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
    <c:out value="管理员欢迎您!"/>
</c:if>

<%--自闭合标签--%>
<c:out value="${isAdmin}"/>

c:choose c:when

<%--定义一个变量score,值为85--%>
<c:set var="score" value="55"/>
<c:choose>
    <c:when test="${score>=90}">
        你的成绩为优秀
    </c:when>
    <c:when test="${score>=80}">
        你的成绩为一般
    </c:when>
    <c:when test="${score>=70}">
        你的成绩为良好
    </c:when>
    <c:when test="${score<=60}">
        你的成绩为不及格
    </c:when>
</c:choose>

c:forEach

<%

    ArrayList<String> people = new ArrayList<>();
    people.add(0,"张三");
    people.add(1,"李四");
    people.add(2,"王五");
    people.add(3,"赵六");
    people.add(4,"田六");
    request.setAttribute("list",people);
%>
<%--
var , 每一次遍历出来的变量
items, 要遍历的对象
begin,   哪里开始
end,     到哪里
step,   步长
--%>
<c:forEach var="people" items="${list}">
    <c:out value="${people}"/> <br>
</c:forEach>

<hr>
<c:forEach var="people" items="${list}" begin="1" end="3" step="1" >
    <c:out value="${people}"/> <br>
</c:forEach>

你可能感兴趣的:(java,javaweb)