JavaWeb复习重点内容

Posted 请你喝杯Java.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb复习重点内容相关的知识,希望对你有一定的参考价值。

✅✅作者主页:🔗孙不坚1208的博客
🔥🔥精选专栏:🔗JavaWeb从入门到精通(持续更新中)
📋📋 本文摘要:本篇文章主要分享JavaWeb的学习重点内容。

💞💞觉得文章还不错的话欢迎大家点赞👍➕收藏⭐️➕评论💬支持博主🤞
👉 👉你的一键三连是我更新的最大动力❤️❤️

JavaWeb复习重点

javaweb期末题型有2大类:问答题、编程题

一、问答题7个左右,共40分

1.Servlet的定义、配置(使用xml或注解)

Servlet是用Java编写的服务器端程序,其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类。

Servlet的配置有xml和注解两种方式

xml方式:

<servlet>
	<servlet-name>demo</servlet-name>
    <!--全类名-->
    <servlet-class>web.servlet.ServletDemo</servlet-class>
</servlet>
    
<servlet-mapping>
    <servlet-name>demo</servlet-name>
    <!--url访问的资源名-->
    <url-pattern>/index</url-pattern>
</servlet-mapping>

注解方式:在类上使用注解@WebServlet注解配置

@WebServlet("/demo")
public class ServletDemo implements Servlet 
    // 实现Servlet接口

2.重定向与请求转发的区别,使用API完成重定向和转发

重定向(Redirect)和请求转发(Forward)是两种不同的HTTP请求处理机制。

重定向是在接收到请求后,服务器向客户端返回一个特殊的响应,指示客户端重新向指定的url发送请求,这个过程是完全由客户端完成的,客户端会发送一个新的请求到指定的url,并接收新的响应。重定向经常被用来处理资源的移动,url的更改,或者是需要访问其他网站的情况。

请求转发则是在服务器端将请求转发给另一个资源进行处理,这个过程是在服务器内部完成的。客户端发送请求到服务器,服务器会将请求转发到另一个资源进行处理,然后将处理结果返回给客户端。请求转发经常被用来组合多个资源进行处理,例如在JSP中使用include指令将多个JSP页面组合在一起。

重定向:

response.sendRedirect("http://www.example.com");

转发:

RequestDispatcher dispatcher = request.getRequestDispatcher("/example.jsp");
dispatcher.forward(request, response);

在以上示例代码中,responserequestjavax.servlet.http.HttpServletResponsejavax.servlet.http.HttpServletRequest的实例对象。重定向通过调用sendRedirect()方法并传入要重定向到的URL字符串来实现。请求转发则通过创建一个RequestDispatcher对象,该对象通过getRequestDispatcher()方法获取,并传入要转发到的资源的路径,然后调用forward()方法来实现。在请求转发中,requestresponse对象被传递给了要转发到的资源。

需要注意的是,重定向会向客户端发送一个新的请求,因此客户端的URL会发生改变,而请求转发是在服务器内部完成的,客户端的URL不会改变。

3.重定向与请求转发的优缺点

重定向的优点:

  1. 简单易用:使用response.sendRedirect()方法非常简单,可以很容易地将客户端重定向到其他URL。
  2. 安全性高:重定向会向客户端发送一个新的请求,因此客户端的URL会发生改变,可以避免某些安全漏洞,比如在表单提交后刷新页面导致的重复提交等。

重定向的缺点:

  1. 频繁网络请求:重定向会向客户端发送一个新的请求,会导致网络请求的增加,影响性能。
  2. 无法访问原始请求对象:重定向会生成一个新的请求对象,因此无法访问原始请求对象,如原始的HTTP请求头等。

请求转发的优点:

  1. 性能高:请求转发是在服务器内部完成的,不会向客户端发送新的请求,因此不会增加网络请求,性能比较高。
  2. 可以访问原始请求对象:请求转发可以访问原始请求对象,如原始的HTTP请求头等。

请求转发的缺点:

  1. 不适用于跨域请求:由于请求转发只能转发到同一Web应用程序中的资源,因此不能用于跨域请求。
  2. 不支持修改URL:请求转发是在服务器内部完成的,客户端无法感知,也无法修改URL。

4.给出了Servlet的代码实现,让大家用JSP来实现该功能

这个参考课本

使用JSP实现重定向和请求转发的示例代码:

重定向:

<%
  response.sendRedirect("http://www.example.com");
%>

请求转发:

<jsp:forward page="/example.jsp" />

jsp转换如下

<jps:useBean id="user" class="package.User" pageScope="session"/>

<%
	if(session.getAttribute("user")) == null 
        User user = new new User();
        session.getAttribute("user",user);
    
%>

5.JavaBean的规范,应该详细掌握

JavaBean是一种符合Java语言规范的特殊类,通常用于存储和操作数据。JavaBean类应该遵循以下规范:

  1. 应该提供一个无参的构造方法:JavaBean的构造方法应该是无参的,这样可以方便地在其他类中创建JavaBean的实例。无参构造方法可以通过手动编写或者使用编译器自动生成的方式实现。
  2. 所有属性应该私有化:JavaBean的属性应该使用private修饰符进行私有化,通过提供公共的getter和setter方法来访问属性。
  3. getter和setter方法的命名应该符合JavaBean命名规范:JavaBean的getter和setter方法应该遵循一定的命名规范。getter方法的名称应该以“get”开头,setter方法的名称应该以“set”开头,后面跟着属性名的首字母大写的形式。
  4. 应该提供默认的toString方法:JavaBean应该提供一个默认的toString方法,以便在调试和日志记录时方便查看JavaBean的属性值。
  5. 应该提供其他有用的方法:除了getter和setter方法以外,JavaBean还可以提供一些其他的有用方法,例如校验方法、计算方法等。

6.给出了Servlet的代码实现,让大家用JSTL来实现该功能

这个参考课本

JSTL(JavaServer Pages Standard Tag Library)是一个标准的JSP标签库,提供了一些常用的标签,可以方便地实现一些常见的操作,包括重定向和转发。以下是使用JSTL实现重定向和转发的示例代码:

重定向:

<c:redirect url="http://www.example.com" />

以上代码中,<c:redirect>标签用于实现重定向,url属性指定要重定向到的URL字符串。

请求转发:

<c:forward page="/example.jsp" />

以上代码中,<c:forward>标签用于实现请求转发,page属性指定要转发到的JSP页面的路径。

7.过滤器的概念,写出一个过滤器类

过滤器(Filter)是Java Web应用程序中的一个重要组件,可以拦截客户端请求和服务器响应,对它们进行预处理和后处理,实现一些通用的功能,例如日志记录、权限控制、字符编码转换等。

一个过滤器类必须实现javax.servlet.Filter接口,并重写其中的doFilter()方法。以下是一个简单的过滤器类的示例代码,实现了字符编码转换的功能:

import javax.servlet.*;
import java.io.IOException;

@WebFilter(filterName = "CharacterEncodingFilter", urlPatterns = "/*")
public class CharacterEncodingFilter implements Filter 
    private String encoding;

    public void init(FilterConfig config) throws ServletException 
        // 读取初始化参数,设置字符编码
        encoding = config.getInitParameter("encoding");
    

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
        // 设置请求和响应的字符编码
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);

        // 调用后续的过滤器或Servlet/JSP处理请求
        chain.doFilter(request, response);
    

    public void destroy() 
        // 释放资源
    

以上代码中,使用@WebFilter注解配置了过滤器的名称和URL模式。filterName属性指定过滤器的名称,urlPatterns属性指定需要过滤的URL模式。在此示例中,过滤器会拦截所有的请求。

以上代码中,CharacterEncodingFilter类实现了javax.servlet.Filter接口,并重写了其中的init()doFilter()destroy()方法。init()方法在过滤器初始化时被调用,读取初始化参数并设置字符编码;doFilter()方法用于实现过滤功能,设置请求和响应的字符编码,并调用后续的过滤器或Servlet/JSP处理请求;destroy()方法在过滤器销毁时被调用,释放资源。

需要注意的是,过滤器配置除了注解的这种方式也可以在Web应用程序的web.xml文件中,通过过滤器链(Filter Chain)的方式实现多个过滤器的协同工作。过滤器的顺序可以通过<filter-mapping>元素中的<url-pattern>子元素来指定。

8.JPA中实体类、以及实体关系映射,一对一、一对多

在 JPA 中,实体类是指映射到数据库表的 Java 类。实体类通常具有以下特点:

  1. 实体类使用 @Entity 注解进行标记。
  2. 实体类的每个实例对应数据库表中的一行数据。
  3. 实体类的属性对应数据库表中的列。

JPA 中的实体关系映射用于描述实体类之间的关联关系,包括一对一、一对多、多对一和多对多关系。其中,一对一和一对多是较为常见的关系类型。

一对一关系映射示例:

@Entity
public class Person 
    @Id
    private Long id;

    private String name;

    @OneToOne(cascade = CascadeType.ALL)
    private Address address;


@Entity
public class Address 
    @Id
    private Long id;

    private String street;

    private String city;

    private String country;

    @OneToOne(mappedBy = "address")
    private Person person;

上述代码中,PersonAddress 分别是两个实体类。它们之间的关系是一对一,通过 @OneToOne 注解进行映射。Person 实体类中的 address 属性使用 @OneToOne 注解,表示它与 Address 实体类是一对一关系。Address 实体类中的 person 属性也使用了 @OneToOne 注解,但是它的 mappedBy 属性指向了 Person 实体类的 address 属性,表示这是一个双向关联,并且由 Person 实体类来维护关系。

一对多关系映射示例:

@Entity
public class Department 
    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
    private List<Employee> employees;


@Entity
public class Employee 
    @Id
    private Long id;

    private String name;

    private String email;

    @ManyToOne
    private Department department;

上述代码中,DepartmentEmployee 分别是两个实体类。它们之间的关系是一对多,通过 @OneToMany@ManyToOne 注解进行映射。Department 实体类中的 employees 属性使用了 @OneToMany 注解,表示它与 Employee 实体类是一对多关系。Employee 实体类中的 department 属性使用了 @ManyToOne 注解,表示它与 Department 实体类是多对一关系,并且它的 department 属性指向了 Department 实体类的 employees 属性,表示这是一个双向关联,并且由 Department 实体类来维护关系。

需要注意的是,上述示例中使用了 JPA 中的级联操作(CascadeType.ALL),表示当父实体被删除时,子实体也将被删除。这种级联操作可能会对数据产生不可逆的影响,因此需要谨慎使用。

9.Spring控制器的类的编写、路径的配置、注入组件、返回Json数据

在 Spring 中,控制器是指负责处理请求和响应的组件,通常由一个 Java 类实现。以下是 Spring 控制器类的编写、路径配置、注入组件和返回 JSON 数据的示例:

@Controller
@RequestMapping("/api/users")
public class UserController 
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/id")
    @ResponseBody
    public User getUserById(@PathVariable Long id) 
        return userService.getUserById(id);
    
    
    @PostMapping("/")
    @ResponseBody
    public User createUser(@RequestBody User user) 
        return userService.createUser(user);
    
    
    @PutMapping("/id")
    @ResponseBody
    public User updateUser(@PathVariable Long id, @RequestBody User user) 
        return userService.updateUser(id, user);
    
    
    @DeleteMapping("/id")
    @ResponseBody
    public void deleteUser(@PathVariable Long id) 
        userService.deleteUser(id);
    
    

在上述示例中,我们定义了一个名为 UserController 的控制器类,并使用 @Controller 注解标记它。@RequestMapping 注解用于配置控制器类的路径前缀,即 /api/users。这意味着,当请求的路径以 /api/users 开头时,Spring 将会把请求交给该控制器类来处理。

在控制器类中,我们使用了 @Autowired 注解来自动注入一个名为 userService 的组件。这里假设 UserService 是一个已经定义好的服务组件,可以使用 @Service 注解标记它。

控制器类中的方法使用了不同的 HTTP 方法注解,包括 @GetMapping@PostMapping@PutMapping@DeleteMapping,用于定义请求的 HTTP 方法类型。这些注解后面跟随的路径参数用于定义具体的请求路径。例如,@GetMapping("/id") 表示可以处理 /api/users/id 这样的 GET 请求。

在方法中,我们使用了 @ResponseBody 注解来表示将方法的返回值直接作为响应内容返回给客户端。这里,我们返回的是一个 User 类型的对象,Spring 会将它自动转换为 JSON 格式并返回给客户端。需要注意的是,为了能够让 Spring 自动完成 JSON 转换,我们需要在项目中引入相应的 JSON 库,例如 Jackson。

总的来说,Spring 控制器类提供了方便的方式来处理 HTTP 请求和响应,可以通过注解配置路径和 HTTP 方法,并且支持自动注入组件和返回 JSON 数据等常用功能。

二、编程题4个题,共60分

1.题目给出了数据库、表等信息,要求使用JDBC完成增删改查这些操作,可能需要事务

使用 JDBC 完成增删改查操作通常需要以下步骤:

  1. 加载数据库驱动。
  2. 建立数据库连接。
  3. 创建 Statement 或 PreparedStatement 对象。
  4. 执行 SQL 语句。
  5. 处理查询结果。
  6. 释放资源。

以下是一个使用 JDBC 实现增删改查操作的示例:

public class UserDao 
    
    private Connection conn;
    
    public UserDao(Connection conn) 
        this.conn = conn;
    
    
    public void createUser(User user) throws SQLException 
        String sql = "INSERT INTO users(name, email, password) VALUES (?, ?, ?)";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setString(1, user.getName());
        stmt.setString(2, user.getEmail());
        stmt.setString(3, user.getPassword());
        stmt.executeUpdate();
        stmt.close();
    
    
    public void updateUser(User user) throws SQLException 
        String sql = "UPDATE users SET name=?, email=?, password=? WHERE id=?";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setString(1, user.getName());
        stmt.setString(2, user.getEmail());
        stmt.setString(3, user.getPassword());
        stmt.setLong(4, user.getId());
        stmt.executeUpdate();
        stmt.close();
    
    
    public void deleteUser(long id) throws SQLException 
        String sql = "DELETE FROM users WHERE id=?";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setLong(1, id);
        stmt.executeUpdate();
        stmt.close();
    
    
    public User getUserById(long id) throws SQLException 
        String sql = "SELECT id, name, email, password FROM users WHERE id=?";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setLong(1, id);
        ResultSet rs = stmt.executeQuery();
        User user = null;
        if (rs.next()) 
            user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            user.setEmail(rs.getString("email"));
            user.setPassword(rs.getString("password"));
        
        rs.close();
        stmt.close();
        return user;
    
    

上述代码中,我们定义了一个 UserDao 类,用于操作名为 users 的数据库表。其中的四个方法分别实现了创建用户、更新用户、删除用户和根据用户 ID 查询用户的功能。在这些方法中,我们使用了 PreparedStatement 对象来执行 SQL 语句,并通过设置占位符的方式传递参数。通过这种方式,可以有效避免 SQL 注入等安全问题。

如果需要使用事务,可以将上述方法放到一个事务中执行。以下是一个示例:

public void createUserWithTransaction(User user) throws SQLException 
    conn.setAutoCommit(false);
    try 
        createUser(user);
        conn.commit();
     catch (SQLException e) 
        conn.rollback();
        throw e;
     finally 
        conn.setAutoCommit(true);
    

在这个方法中,我们通过将 autoCommit 属性设置为 false,来启用手动事务。在执行完所有操作后,我们可以选择提交或回滚事务。同时,为了保证代码的健壮性,需要在 finally 块中将 autoCommit 属性设置回 true

2.编写Servlet接收请求参数,并保存到某个作用域

@WebServlet("/example")
public class ExampleServlet extends HttpServlet 

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
        String name = request.getParameter("name");
        String email = request.getParameter("email");
        String password = request.getParameter("password");

        // 将参数保存到 session 作用域
        HttpSession session = request.getSession();
        session.setAttribute("name", name);
        session.setAttribute("email", email);
        session.setAttribute("password", password);

        // 将参数保存到 request 作用域
        request.setAttribute("name", name);
        request.setAttribute("email", email);
        request.setAttribute("password", password);

        // 将参数保存到 application 作用域
        ServletContext context = getServletContext();
        context.setAttribute("name", name);
        context.setAttribute("email", email);
        context.setAttribute("password", password);

        // 重定向到结果页面
        response.sendRedirect(request.getContextPath() + "/result.jsp");
    


在上述代码中,我们在 doPost 方法中,分别将参数保存到 session、request 或 application 作用域中。在 session 中保存参数的方式与之前的示例类似,使用 request.getSession() 方法获取 HttpSession 对象,并调用其 setAttribute 方法将参数保存到 session 作用域中。

request 作用域中保存参数的方式也很类似,只需要使用 request.setAttribute 方法将参数保存到 request 作用域中即可。

application 作用域中保存参数也非常简单,只需要使用 getServletContext() 方法获取 ServletContext 对象,并调用其 setAttribute 方法将参数保存到 application 作用域中即可。

需要注意的是,在将参数保存到不同作用域中时,需要使用不同的对象来调用 setAttribute 方法。除此之外,其他代码与之前的示例相同,最终通过 response.sendRedirect 方法重定向到结果页面。

3.JPA的编程题,题目给出数据库和表,让大家使用JPA完成实体类及使用EntityManager完成增删改查操作

假设有一个表名为 user,包含以下字段:

FieldType
idINT
nameVARCHAR(100)
ageINT
emailVARCHAR(100)
passwordVARCHAR(100)

接下来,我们需要使用 JPA 完成实体类及使用 EntityManager 完成增删改查操作。

首先,我们需要定义一个实体类 User,对应 user 表中的一条记录:

@Entity
@Table(name = "user")
public class User 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    private Integer age;

    private String email;

    private String password;

    // getters and setters

在上述代码中,我们使用 @Entity 注解表示这是一个实体类,使用 @Table 注解指定了实体对应的表名为 user。同时,我们在类中定义了实体对应的属性,并使用 @Id@GeneratedValue 注解表示该属性为实体的唯一标识,并指定了该属性的生成策略为自增长。

接下来,我们可以使用 EntityManager 对实体进行增删改查操作。以下是一个示例:

public class UserDao 

    @PersistenceContext
    private EntityManager entityManager;

    // 添加用户
    public void addUser(User user) 
        entityManager.persist(user);
    

    // 根据 id 查询用户
    public User getUserById(Integer id) 
        return entityManager.find(User.class, id)
JavaWeb--深入Servlet与JSP(运行原理)

复习复习!!!搞起来!!Servlet和JSP是Java EE规范最基本成员,他们是Java Web开发的重点知识,即使我们经常使用框架开发后端,但是我们还是很必要去理解他们的原理的。

文章结构:(1)剖析Servlet;(2)剖析JSP;


一、剖析Servlet:

(1)概述:

Servlet是一种独立于平台和协议的服务器端的Java应用程序,可以生成动态的web页面。它担当Web浏览器或其他http客户程序发出请求、与http服务器上的数据库或应用程序之间交互的中间层。

Servlet是用Java编写的Server端程序,它与协议和平台无关。Servlet运行于Java服务器中。
Java Servlet可以动态地扩展服务器的能力,并采用请求-响应模式提供Web服务。
Servlet是使用Java Servlet应用程序设计接口及相关类和方法的Java程序。它在Web服务器上或应用服务器上运行并扩展了该服务器的能力。Servlet装入Web服务器并在Web服务器内执行。
Servlet是以Java技术为基础的服务器端应用程序组件,Servlet的客户端可以提出请求并获得该请求的响应,它可以是任何Java程序、浏览器或任何设备。

(2)基本知识:

1.配置:

编辑好的servlet源文件并不能响应用户请求,还必须将其编译成class文件,将编译好的class文件放到WEB-INF/classes路径下,如果servlet有包,则还需要将class文件放到包路径下。

2.生命周期:

这里写图片描述

编写的JSP页面最终将由web容器编译成对应的servlet,当servlet在容器中运行时,其实例的创建及销毁等都不是有程序猿决定的,而是由web容器进行控制的。

servlet容器负责加载和实例化Servlet,在容器启动时根据设置决定是在启动时初始化(loadOnStartup大于等于0在容器启动时进行初始化,值越小优先级越高),还是延迟初始化直到第一次请求前;

初始化:

init(),执行一些一次性的动作,可以通过ServletConfig配置对象,获取初始化参数,访问ServletContext上下文环境;

请求处理:

servlet容器封装Request和Response对象传给对应的servlet的service方法,对于HttpServlet,就是HttpServletRequest和HttpServletResponse; HttpServlet中使用模板方法模式,service方法根据HTTP请求方法进一步分派到doGet,doPost等不同的方法来进行处理;
对于HTTP请求的处理,只有重写了支持HTTP方法的对应HTTP servlet方法(doGet),才可以支持,否则放回405(Method Not Allowed)。

3.访问servlet的配置参数:

配置servlet时,还可以增加额外的配置参数,通过使用配置参数,可以实现提供更好的可移植性,避免将参数以编码方式写在程序代码中。

配置参数有两种方式:
(1)通过@WebServlet的initParams属性来指定。
(2)通过在web.xml文件的

4.Servlet的数量:

Servlet默认是线程不安全的,一个容器中只有每个servlet一个实例。

StandardWrapper源码中写明,这个类负责Servlet的创建,其中SingleThreadModule模式下创建的实例数不能超过20个,也就是同时只能支持20个线程访问这个Serlvet,因此,这种对象池的设计会进一步限制并发能力和可伸缩性。

5.缺点:

开发效率低、 程序可移植性差、 程序可维护性差

6.标准mvc模式中的servlet:

仅作为控制器使用,JavaEE应用架构正是遵循mvc模式的,其中JSP仅作为表现层技术,其作用有两点:1.负责收集用户请求参数;2. 将应用的处理结果、状态、数据呈现给用户。

7.线程不安全 :

servlet中默认线程不安全,单例多线程,因此对于共享的数据(静态变量,堆中的对象实例等)自己维护进行同步控制,不要在service方法或doGet等由service分派出去的方法,直接使用synchronized方法,很显然要根据业务控制同步控制块的大小进行细粒度的控制,将不影响线程安全的耗时操作移出同步控制块;

Servlet多线程机制背后有一个线程池在支持,线程池在初始化初期就创建了一定数量的线程对象,通过提高对这些对象的利用率,避免高频率地创建对象,从而达到提高程序的效率的目的。(由线程来执行Servlet的service方法,servlet在Tomcat中是以单例模式存在的, Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要特别注意。线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径)

8.异步处理:

在Servlet中等待是一个低效的操作,因为这是阻塞操作。

异步处理请求能力,使线程可以返回到容器,从而执行更多的任务。当开始异步处理请求时,另一个线程或回调可以:(1)产生响应;或者,(2)请求分派;或者,(3)调用完成;

关键方法:

启用:让servlet支持异步支持:asyncSupported=true;
启动AsyncContextasyncContext=req.startAsyncContext();或startAsyncContext(req,resp);
完成:asyncContext.complete();必须在startAsync调用之后,分派进行之前调用;同一个AsyncContext不能同时调用dispatch和complete
分派:asyncContext.dispatch();dispatch(Stringpath);dispatch(ServletContextcontext,Stringpath); 不能在complete之后调用; 从一个同步servlet分派到异步servlet是非法的;
超时:
asyncContext.setTimeout(millis); 超时之后,将不能通过asyncContext进行操作,但是可以执行其他耗时操作;
在异步周期开始后,容器启动的分派已经返回后,调用该方法抛出IllegalStateException;如果设置成0或小于0就表示notimeout; 超时表示HTTP连接已经结束,HTTP已经关闭,请求已经结束了。

启动新线程 :

通过AsyncCOntext.start(Runnable)方法,向线程池提交一个任务,其中可以使用AsyncContext(未超时前);
事件监听:addListener(newAsyncListener{…});
onComplete:完成时回调,如果进行了分派,onComplete方法将延迟到分派返回容器后进行调用;
onError:可以通过AsyncEvent.getThrowable获取异常;
onTimeout:超时进行回调;
onStartAsync:在该AsyncContext中启动一个新的异步周期(调用startAsyncContext)时,进行回调;

超时和异常处理,步骤:

(1)调用所有注册的AsyncListener实例的onTimeout/onError;
(2)如果没有任何AsyncListener调用AsyncContext.complete()或AsyncContext.dispatch(),执行一个状态码为HttpServletResponse .SC_INTERNAL_SERVER_ERROR出错分派;
(3)如果没有找到错误页面或者错误页面没有调用AsyncContext.complete()/dispatch(),容器要调用complete方法;

servlet生命终止:

servlet容器确定从服务中移除servlet时,可以通过调用destroy()方法将释放servlet占用的任何资源和保存的持久化状态等。调用destroy方法之前必须保证当前所有正在执行service方法的线程执行完成或者超时;
之后servlet实例可以被垃圾回收,当然什么时候回收并不确定,因此destroy方法是是否必要的。

(3)运行原理:

当Web服务器接收到一个HTTP请求时,它会先判断请求内容——如果是静态网页数据,Web服务器将会自行处理,然后产生响应信息;如果牵涉到动态数据,Web服务器会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例来处理,结果会送回Web服务器,再由Web服务器传回用户端。

针对同一个Servlet,Servlet容器会在第一次收到http请求时建立一个Servlet实例,然后启动一个线程。第二次收到http请求时,Servlet容器无须建立相同的Servlet实例,而是启动第二个线程来服务客户端请求。所以多线程方式不但可以提高Web应用程序的执行效率,也可以降低Web服务器的系统负担。

下图粗暴解释了请求到容器流程

这里写图片描述

下图解释了请求到容器到servlet周期流程

这里写图片描述

文字解说:

1.客户发出请求—>Web 服务器转发到Web容器Tomcat;

2.Tomcat主线程对转发来用户的请求做出响应创建两个对象:HttpServletRequest和HttpServletResponse;

3.从请求中的URL中找到正确Servlet,Tomcat为其创建或者分配一个线程,同时把步骤2创建的两个对象传递给该线程;

4.Tomcat调用Servlet的servic()方法,根据请求参数的不同调用doGet()或者doPost()方法;

5.假设是HTTP GET请求,doGet()方法生成静态页面,并组合到响应对象里;

Servlet线程结束时:Tomcat将响应对象转换为HTTP响应发回给客户,同时删除请求和响应对象。

可以理解Servlet的生命周期:Servlet类加载(对应3步);Servlet实例化(对应3步);调用init方法(对应3步);调用service()方法(对应4、5步);;调用destroy()方法(对应6步)。

注意:

1.创建Servlet对象的时机:

Servlet容器启动时:读取web.xml配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,同时将ServletConfig对象作为参数来调用Servlet对象的init方法。

在Servlet容器启动后:客户首次向Servlet发出请求,Servlet容器会判断内存中是否存在指定的Servlet对象,如果没有则创建它,然后根据客户的请求创建HttpRequest、HttpResponse对象,从而调用Servlet 对象的service方法。

Servlet Servlet容器在启动时自动创建Servlet,这是由在web.xml文件中为Servlet设置的属性决定的。从中我们也能看到同一个类型的Servlet对象在Servlet容器中以单例的形式存在。

2.在Servlet接口和GenericServlet中是没有doGet()、doPost()等等这些方法的,HttpServlet中定义了这些方法,但是都是返回error信息,所以,我们每次定义一个Servlet的时候,都必须实现doGet或doPost等这些方法。我们经常使用的httpServlet是继承于GenericServlet实现的。


二、剖析JSP

(1)概述:

JSP和Servlet的本质是一样的,因为JSP最终需要编译成Servlet才能运行,换句话说JSP是生成Servler的草稿文件。

JSP就是在HTML中嵌入Java代码,或者使用JSP标签,包括使用用户自定义标签,从而可以动态的提供内容。早起JSP应用比较广泛,一个web应用可以全部由JSP页面组成,只需要少量的JavaBean即可,但是这样导致了JSP职责过于复杂,这是Java EE标准的出现无疑是雪中送炭,因此JSP慢慢发展成单一的表现技术,不再承担业务逻辑组件以及持久层组件的责任。

原理概述:(一会详解)

JSP的本质是servlet,当用户指定servlet发送请求时,servlet利用输出流动态生成HTML页面。由于包含大量的HTML标签。静态文本等格式导致servlet的开发效率极低,所有的表现逻辑,包括布局、色彩及图像等,都必须耦合在Java代码中,起静态的部分无需Java程序控制,只有那些需要从数据库读取或者需要动态生成的页面内容才使用Java脚本控制。
因此,JSP页面内容有以下两部分组成:

静态部分:HTML标签

动态部分:Java脚本

(2)基本知识:

指令就省略了吧,随便查都有一堆。

重点讲讲它的内置对象:

首先,我们可以自己去一个目录去看看jsp编译成servlet的代码。目录是:你的eclipse的工作目录下:比如:E:\\eclipse\\workplace.metadata.plugins\\org.eclipse.wst.server.core\\tmp0\\work\\
从中,我们可以看到有九个隐藏对象,一些就final了,一些没有。

1.request(使用最多):HttpServletRequest的一个对象(在JSP页面可能会用到)。

Request范围只针对服务器端跳转。用于接收客户端发送而来的请求信息。
注意:单一的参数可以使用getParameter()接收,而一组参数要用getParameterValues()接收。但要小心,如果getParameter和getParameterValues接收参数时,返回内容是null,就可能产生NullPointerException,所以最好判断接收来的参数是否为null。
获取头信息的名称,可使用request的getHeaderNames()方法;而要想取出每个头信息的内容则需使用getHeader()方法。比如:语言、主机、Cookie等。

2.Response:

HttpServletResponse的一个对象(在JSP页面中几乎不会调用response的任何方法)

主要作用:对客户端的请求进行回应,将Web服务器处理后的结果发回给客户端。
设置头信息:客户端与服务器端经常需要发送许多额外信息。服务器端可通过setHeader方法,将头信息设置为refresh,并指定刷新时间,还有跳转的路径URL。如:例子就是那些页面经常提示的“3秒后跳转到首页”这样的操作。
如果定时为0,则为无条件跳转。注意:定时跳转属于客户端跳转。而且这种设置跳转头信息的方式,单纯html也可以做,所以要结合实际考虑,如需请求的是动态页则需JSP进行编写

3.pageContext:

页面的上下文,表示当前页面,是一个PageContext的一个对象,可以从该对象中获取到其他8个隐含对象,也可以从中获取到当前页面的其他信息。(学习自定义标签时使用它,JSP页面上很少直接使用,1`但很重要)。作用范围仅在当前页面。实际上pageContext可以设置任意范围的属性,而其他操作也是对这一功能的再度包装而已。但一般习惯于使用pageContext对象设置保存在一页范围的属性。很少使用他进行设置其他范围的属性。

4.session:

代表浏览器和服务器的一次会话,是HttpSession的一个对象,后面详细学习。这个session属性设置后,可在任何一个与设置页面相关的页面中获取。也就是不管是客户端跳转还是服务器端跳转都可以取得属性。但是如果再打开一个新的浏览器访问该jsp页面,则无法取得session属性。因为每个新的浏览器连接上服务器后就是一个新的session。

5.application:

代表当前web应用。是ServletContext对象。这个设置的属性可让所有用户(session)都看得见。这样的属性保存在服务器上。

6.config:

前JSP对应的Servlet的ServletConfig对象(开发的时候几乎不用)。若需要访问当前JSP配置的初始化参数,需要通过映射的地址才可以。
映射JSP方式:

这里写图片描述

7.out:

作用:完成页面的输出操作。但在开发中,一般是使用表达式完成输出的。
JspWriter对象,经常调用out.println() 可以直接把字符串打印到浏览器上。

8.page

指向当前JSP对应的Servlet对象的引用,但为Object类型,只能调用Object类的方法(几乎不使用)。就是当前JSP对象。

9.exception:

在声明了page 指令的isErrorPage=”true”时,才可以使用。<%@ page isErrorPage=”true”%>

大致使用频率:

pageContext,request,session,application;(对属性的作用域的范围从小到大)

out,response,config,page,exception

(3)JSP运行原理:

这里写图片描述 
这里写图片描述

1.WEB容器(Servlet引擎)接收到以.jsp为扩展名的URL的访问请求时,容器会把访问请求交给JSP引擎去处理

2.每个JSP页面在第一次被访问时,JSP引擎将它翻译成一个Servlet源程序,接着再把这个Servlet源程序编译成Servlet的.class类文件,然后再由WEB容器(Servlet引擎)像调用普通Servlet程序一样的方式来装载和解释执行这个由JSP页面翻译成的Servlet程序,并执行该servlet实例的jspInit()方法(jspInit()方法在Servlet的生命周期中只被执行一次)。。

3.然后创建并启动一个新的线程,新线程调用实例的jspService()方法。(对于每一个请求,JSP引擎会创建一个新的线程来处理该请求。如果有多个客户端同时请求该JSP文件,则JSP引擎会创建多个线程,每个客户端请求对应一个线程)。

4.浏览器在调用JSP文件时,Servlet容器会把浏览器的请求和对浏览器的回应封装成HttpServletRequest和HttpServletResponse对象,同时调用对应的Servlet实例中的jspService()方法,把这两个对象作为参数传递到jspService()方法中。

5.jspService()方法执行后会将HTML内容返回给客户端。

如果JSP文件被修改了,服务器将根据设置决定是否对该文件进行重新编译。如果需要重新编译,则将编译结果取代内存中的Servlet,并继续上述处理过程。 如果在任何时候由于系统资源不足,JSP引擎将以某种不确定的方式将Servlet从内存中移去。当这种情况发生时,jspDestroy()方法首先被调用, 然后Servlet实例便被标记加入“垃圾收集”处理。

补充:

1.JSP规范也没有明确要求JSP中的脚本程序代码必须采用Java语言,JSP中的脚本程序代码可以采用Java语言之外的其他脚本语言来编写,但是JSP页面最终必须转换成JavaServlet程序。

2.可以在WEB应用程序正式发布之前,将其中的所有JSP页面预先编译成Servlet程序。

3.以多线程方式执行可大大降低对系统的资源需求,提高系统的并发量及响应时间,但应该注意多线程的编程限制,由于该Servlet始终驻于内存,所以响应是非常快的。

4.虽然JSP效率很高,但在第一次调用时由于需要转换和编译而有一些轻微的延迟。在jspInit()中可以进行一些初始化工作,如建立与数据库的连接、建立网络连接、从配置文件中获取一些参数等,而在jspDestory()中释放相应的资源。


参考博客:

http://blog.csdn.net/fengdongkun/article/details/8159381

http://www.cnblogs.com/mlloc-clove/p/3549777.html


好了,JavaWeb–深入Servlet与JSP(运行原理)讲完了。本博客是我复习阶段的一些笔记,拿来分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!

转载:JackFrost的博客

以上是关于JavaWeb复习重点内容的主要内容,如果未能解决你的问题,请参考以下文章

JavaWeb核心之Servlet

JavaWeb核心之Servlet

Java Web

Javaweb复习资料

Javaweb复习资料

JavaWeb期末复习