JavaWeb

Servlet

Tomcat:Web 应用服务器,属于轻量级应用服务器,也叫Servlet容器

1. 生命周期

生命周期方法:

  • void init(ServletConfig):出生之后(1次);
  • void service(ServletRequest request, ServletResponse response):每次处理请求时都会被调用;
  • void destroy():临死之前(1次);

特性:
 单例,一个类只有一个对象;当然可能存在多个Servlet类!

2. 实现Servlet的方式

实现Servlet有三种方式:

  • 实现javax.servlet.Servlet接口;
  • 继承javax.servlet.GenericServlet类;
  • 继承javax.servlet.http.HttpServlet类;

通常我们会去继承HttpServlet类来完成我们的Servlet

3. 常用方法

1. HttpServletRequest方法:

  • String getParameter(String paramName)
    获取指定请求参数的值;
  • String getMethod()
    获取请求方法,例如GET或POST;
  • String getHeader(String name)
    获取指定请求头的值;
  • void setCharacterEncoding(String encoding)
    设置请求体的编码!因为GET请求没有请求体,所以这个方法只只对POST请求有效。当调用request.setCharacterEncoding(“utf-8”)之后,再通过getParameter()方法获取参数值时,那么参数值都已经通过了转码,即转换成了UTF-8编码。所以,这个方法必须在调用getParameter()方法之前调用!
  • request.getRequestDispatcher(“/Servlet
    Test”).forward(request,response)
    :转发

2. HttpServletResponse方法:

  • PrintWriter getWriter():获取字符响应流,使用该流可以向客户端输出响应信息。例如
    response.getWriter(). print(“<h1>Hello JavaWeb!</h1>”);
  • ServletOutputStream getOutputStream():获取字节响应流,当需要向客户端响应字节数据时,需要使用这个流,例如要向客户端响应图片;
  • void setCharacterEncoding(String encoding) :用来设置字符响应流的编码,例如在调用setCharacterEncoding(“utf-8”);之后,再response.getWriter()获取字符响应流对象,这时的响应流的编码为utf-8,使用response.getWriter()输出的中文都会转换成utf-8编码后发送给客户端;
  • void setHeader(String name, String value) :向客户端添加响应头信息,例如setHeader(“Refresh”, “3;url=http://www.itcast.cn”),表示3秒后自动刷新到http://www.itcast.cn;
  • void setContentType(String contentType) :该方法是setHeader(“content-type”, “xxx”)的简便方法,即用来添加名为content-type响应头的方法。content-type响应头用来设置响应数据的MIME类型,例如要向客户端响应jpg的图片,那么可以setContentType(“image/jepg”),如果响应数据为文本类型,那么还要台同时设置编码,例如setContentType(“text/html;chartset=utf-8”)表示响应数据类型为文本类型中的html类型,并且该方法会调用setCharacterEncoding(“utf-8”)方法;
  • void sendError(int code, String errorMsg) :向客户端发送状态码,以及错误消息。例如给客户端发送404:response(404, “您要查找的资源不存在!”)。
  • response.sendRedirect(“http:…..”):重定向某个地址
    3. ServletConfig方法:
    ServletConfig对象是由服务器创建的,然后传递给Servlet的init()方法,你可以在init()方法中使用它
  • String getServletName() :获取Servlet在web.xml文件中的配置名称,即<servlet-name>指定的名称;
  • ServletContext getServletContext() :用来获取ServletContext对象。
  • String getInitParameter(String name) :用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
  • Enumeration getInitParameterNames() :用来获取在web.xml中配置的所有初始化参数名称;
    元素中还可以配置初始化参数:

4. Servlet与线程安全

因为一个类型的Servlet只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求,那么Servlet是否为线程安全的呢?答案是:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!
所以我们不应该在Servlet中便宜创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。

5. ServletContext概述

服务器会为每个应用创建一个ServletContext对象:

  • ServletContext对象的创建是在服务器启动时完成的;
  • ServletContext对象的销毁是在服务器关闭时完成的。

ServletContext是JavaWeb四大域对象之一:

  • PageContext;
  • ServletRequest;
  • HttpSession;
  • ServletContext;
    所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据
    setAttribute()、getAttribute()、removeAttribute()

6. 请求转发与重定向比较

  • 请求转发是一个请求,而重定向是两个请求;
  • 请求转发后浏览器地址栏不会有变化,而重定向会有变化,因为重定向是两个请求;
  • 请求转发的目标只能是本应用中的资源,重定向的目标可以是其他应用;
  • 请求转发对AServlet和BServlet的请求方法是相同的,即要么都是GET,要么都是POST,因为请求转发是一个请求;
  • 重定向的第二个请求一定是GET;

6. 其他

配置servlet初始化时间
<load-on-startup>3</load-on-startup>

通配符使用

  • <url-pattern>/servlet/*<url-patter>:/servlet/a、/servlet/b,都匹配/servlet/*;
  • <url-pattern>*.do</url-pattern>:/abc/def/ghi.do、/a.do,都匹配*.do;
  • <url-pattern>/*<url-pattern>:匹配所有URL;

配置默认参数

1
2
3
4
<context-param>
<param-name>paramName1</param-name>
<param-value>paramValue1</param-value>
</context-param>

获取值:
this.getServletContext(). getInitParameter("paramName1");

获取真实路径
servletContext.getRealPath(“/WEB-INF/b.txt”);

读文件
InputStream in = servletContext. getResourceAsStream(“/WEB-INF/b.txt”);

Class类的getResourceAsStream(String path)

  • 路径以“/”开头,相对classes路径;
  • 路径不以“/”开头,相对当前class文件所有路径,例如在cn.itcast.servlet.MyServlet中执行,那么相对/classes/cn/itcast/servlet/路径;

ClassLoader类的getResourceAsStream(String path)

  • 相对classes路径;

get请求乱码
name = new String(name.getBytes(“iso-8859-1”), “utf-8”);

post乱码
request.setCharacterEncoding(“utf-8”); String name = request.getParameter(“name”);

JSP

jsp其实就是一个servlet,jsp第一次被请求的时候,会编译成class文件,然后再去执行servlet

1. JSP脚本

  • <%…%>:Java语句;
  • <%=…%>:Java表达式;
  • <%!…%>:Java定义类成员;
    其中<%=…%>与out.print()功能是相同的!它们都是向客户端输出,例如:
    <%=s1%>等同于<% out.print(s1); %>

2. JSP指令

JSP中有三大指令:page、include、taglib,page最常用。
page指令

1
<%@page language=”java” contenType=”text/html;charset=gb2312” session=”true” buffer=”64kb” autoFlush=”true” isThreadSafe=”true” info=”text” errorPage=”error.jsp” isErrorPage=”true” isELIgnored=”true” pageEncoding=”gb2312” import=”java.sql.*”%>

web.xml也可以配置错误页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<error-page>

<error-code>404</error-code>
<location>/error404.jsp</location>
</error-page>
<error-page>

<error-code>500</error-code>

<location>/error500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.RuntimeException</exception-type>

<location>/error.jsp</location>
</error-page>

其他指令
<%@include file="filename.jsp"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

九大内置对象

  • out(JspWriter):等同与response.getWriter(),用来向客户端发送文本数据;
  • config(ServletConfig):对应“真身”中的ServletConfig;
  • page(当前JSP的真身类型):当前JSP页面的“this”,即当前对象;
  • pageContext(PageContext):页面上下文对象。
  • exception(Throwable):只有在错误页面中可以使用这个对象;
  • request(HttpServletRequest):即HttpServletRequest类的对象;
  • response(HttpServletResponse):即HttpServletResponse类的对象;
  • application(ServletContext):即ServletContext类的对象;
  • session(HttpSession):即HttpSession类的对象,不是每个JSP页面中都可以使用,如果在某个JSP页面中设置<%@page session=”false”%>,说明这个页面不能使用session。

JSP动作标签

include指令是在编译级别完成的包含,即把当前JSP和被包含的JSP合并成一个JSP,然后再编译成一个Servlet。
include动作标签是在运行级别完成的包含,即当前JSP和被包含的JSP都会各自生成Servlet,然后在执行当前JSP的Servlet时完成包含另一个JSP的Servlet。它与RequestDispatcher的include()方法是相同的!


forward标签的作用是请求转发!forward标签的作用与RequestDispatcher.forward()方法相同

1
2
3
<jsp:include page="/b.jsp">
<jsp:param value="zhangSan" name="username"/>
</jsp:include>

EL表达式

判断字符串长度是否为0或者集合为0${empty “”}
集合对象:${map.key}、${map[‘key’]}

内置对象访问

  • pageScope:${pageScope.name}等同与pageContext.getAttribute(“name”);
  • requestScope:${requestScope.name}等同与request.getAttribute(“name”);
  • sessionScoep: ${sessionScope.name}等同与session.getAttribute(“name”);
  • applicationScope:${applicationScope.name}等同与application.getAttribute(“name”);

其他对象

  • ${header.Host}
  • ${initParam.par} //获取web.xml配的参数
  • ${cookie.}
  • ${pageContext.servletContext.serverInfo}
  • ${pageContext.session.id}
  • ${pageContext.request.requestURL}

JSTL表达式

  1. out和set
    <c:out value=”${aaa}” default=”xxx”/> 等于${aaa}
    c:set var=”a” value=”hello” scope=”session”/> 在session中添加name为a,value为hello的数据。

  2. remove
    <c:remove var="a"/> 删除所有域中name为a的数据!也可以指定:scope=”page”

  3. url
    c:url value="/"/> 输入当前项目路径 如:test/

  4. if

    1
    2
    3
    4
    <c:set var="a" value="hello"/>
    <c:if test="${not empty a }">
    <c:out value="${a }"/>
    </c:if>
  5. choose

    1
    2
    3
    4
    5
    6
    7
    <c:set var="score" value="${param.score }"/>
    <c:choose>
    <c:when test="${score > 100 || score < 0}">错误的分数:${score }</c:when>
    <c:when test="${score >= 90 }">A级</c:when>
    <c:when test="${score >= 60 }">D级</c:when>
    <c:otherwise>E级</c:otherwise>
    </c:choose>
  6. forEach

    1
    2
    3
    4
    <c:set var="sum" value="0" />
    <c:forEach var="i" begin="1" end="10" step="2">
    <c:set var="sum" value="${sum + i}" />
    </c:forEach>
1
2
3
<c:forEach var="item" items="${ns }">
<c:out value="name: ${item }"/><br/>
</c:forEach>
1
2
3
4
5
6
7
<c:forEach var="item" items="${ns }" varStatus="vs">
<c:if test="${vs.first }">第一行:</c:if>
<c:if test="${vs.last }">最后一行:</c:if>
<c:out value="第${vs.count }行: "/>
<c:out value="[${vs.index }]: "/>
<c:out value="name: ${vs.current }"/><br/>
</c:forEach>
  • count:int类型,当前以遍历元素的个数;
  • index:int类型,当前元素的下标;
  • first:boolean类型,是否为第一个元素;
  • last:boolean类型,是否为最后一个元素;
  • current:Object类型,表示当前项目。
    fmt标签库常用标签
    <fmt:formatDate value="${d }" pattern="yyyy-MM-dd HH:mm:ss"/>
    <fmt:formatNumber value="${d2 }" pattern="#.##"/>
    <fmt:formatNumber value="${d1 }" pattern="0.00"/>

其他

在请求url后加上sessionId
<%=response.encodeURL ("/test/index.jsp") %> href='/test/index.jsp;jsessionid=<%=session.getId() %>'

JDBC和数据库

1. JDBC

六大步骤

  1. 加载驱动类
    Class.forName ("oracle.jdbc.OracleDriver");
  2. 建立连接
    Connection conn = DriverManager. getConnection(url,name,password);
  3. 创建statement
    Statement state = conn.createStatement();
  4. 执行SQL语句
    String sql = "select id,name from s_emp"; ResultSet rs = state.executeQuery(sql);
  5. 处理结果集

    1
    2
    3
    4
    5
    6
    while(rs.next()){

    int id = rs.getInt("id");
    String name = rs.getString(2);
    System.out.println(id+" "+name);
    }
  6. 关闭连接
    rs.close(); state.close(); conn.close();

PreparedStatement与Statement区别
PreparedStatement叫预编译声明!
PreparedStatement是Statement的子接口,你可以使用PreparedStatement来替换Statement。
PreparedStatement的好处:

  • 防止SQL攻击;
  • 提高代码的可读性,以可维护性;
  • 提高效率。

预处理的原理
每个pstmt都与一个sql模板绑定在一起,先把sql模板给数据库,数据库先进行校验,再进行编译。执行时只是把参数传递过去而已!
若二次执行时,就不用再次校验语法,也不用再次编译!直接执行!

JDBC中的事务
Connection的三个方法与事务相关:

  • setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值就是true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置false,那么就相当于开启了事务了;con.setAutoCommit(false)表示开启事务!
  • commit():提交结束事务;
  • rollback():回滚结束事务。

2. 事务

事务的四大特性是:

  • 原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
  • 一致性(Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。
  • 隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
  • 持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

    开启事务:start transaction;
    结束事务:commit或rollback。

事务的并发读问题

  • 脏读:读取到另一个事务未提交数据;
  • 不可重复读:两次读取不一致(读取到了另一事务的更新;)
  • 幻读(虚读):读到另一事务已提交数据。

四大隔离级别

  1. SERIALIZABLE(串行化)
     不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;
     性能最差;三种问题都能处理

  2. REPEATABLE READ(可重复读)(MySQL)
     防止脏读和不可重复读,不能处理幻读问题;
     性能比SERIALIZABLE好

  3. READ COMMITTED(读已提交数据)(Oracle)
     防止脏读,没有处理不可重复读,也没有处理幻读;
     性能比REPEATABLE READ好

  4. READ UNCOMMITTED(读未提交数据)
     可能出现任何事务并发问题
     性能最好

MySQL的默认隔离级别为REPEATABLE READ。

3. 连接池

4. 监听器、过滤器、拦截器

  • 拦截器是基于java的反射机制的,而过滤器是基于函数回调
  • 过滤器依赖与servlet容器,而拦截器不依赖与servlet容器
  • 拦截器是AOP的一种实现

过滤器的生命周期

  • init(FilterConfig):服务器启动创建Filter实例,并且每个类型的Filter只创建一个实例,创建完Filter实例后,这个方法只会被执行一次;
  • doFilter(ServletRequest req,ServletResponse res,FilterChain chain):这个方法会在用户每次访问就会执行。
  • destroy():服务器会在创建Filter对象之后,把Filter放到缓存中一直使用,通常不会销毁它。一般会在服务器关闭时销毁Filter对象,在销毁Filter对象之前,服务器会调用Filter对象的destory()方法。
    配置过滤器拦截方式:REQUEST、FORWARD、INCLUDE、ERROR。
    1
    2
    3
    4
    5
    6
    <filter-mapping>
    <filter-name>myfilter</filter-name>
    <url-pattern>/b.jsp</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
lightquant wechat
欢迎您订阅灯塔量化公众号!