15.Servlet

目录

1.Servlet的日常开发 

1.@WebServlet(...此处填写资源路径)

1.那么什么时候Tomcat会启动失败?

2.响应体是文本内容&&字符集编码是uft-8

 3.读取请求参数

4.资源的重定向(redirect)

2.面试问题:GET和POST有什么区别?

3.尝试写一个成绩单

1.错误处理(错误排查)

1.这里列举我遇到的:路径缺少404错误

2.开发者工具长期打开

3.具体每层可能出现的问题

4.  500错误

5.辅助方法

6.理清我们有多少资源,资源支持方法是什么,资源的Path是什么,资源的职责是什么,资源的关系

2.数据的持久化存储(文件 -> MySQL)

1.JDBC

3.拼接HTML比较麻烦(1.模板   2.前后端分离)

 类越来越多,为啥需要这么多类


1.Servlet的日常开发 

1.@WebServlet(...此处填写资源路径)

必须以 / 开头,并且路径不能重复

正常情况"/hello"   "/hello/world"

特殊情况:

(1)通配符"*.do"只要路径后缀名是 .do的都归我管

这是随便写的路径,路径结尾是.do,所以控制台打印了。

 (2)"/"  所有的URL都归它管

 随便写的任何路径都可以访问到,包括.do

有了这个再也不会出现404了

(3)" ",一个空格,这代表根目录URL

1.那么什么时候Tomcat会启动失败?

(1)端口被占用

(2)动态资源的绑定路径有错误的情况

2.响应体是文本内容&&字符集编码是uft-8

1.设置字符集编码

2.设置Content-Type的响应头

3.写响应体

不用调用setHeader(...),直接使用以下代码:

 3.读取请求参数

——读取网页中收集用户填写的信息

GET方法的参数放在query string中

POST方法的参数放在query string和request body中(备注:必须form提交的POST请求)

当GET请求时

1.请求参数放在URL中,格式是name = value&name=value

2.value是中文还是英文均可以在正常读取

3.如果只有name,没有value,读到的是一个空字符串

4.如果连Name都没有,读到的是null

当POST请求时

1.请求参数可以放在URL的query string中,也可以requery body中(必须提交form表单)

格式都是name=value&name=value

2.value是英文没问题,中文有问题,所以需要读取之前,设置请求的字符集编码(req.setCharacterEncording)

3.如果连name都没有,没有value,读到的是一个空的字符""

4.如果连name都没有,读到的是Null

所以,标准读取参数代码如下:

4.资源的重定向(redirect)

3XX + 响应头:Location

临时重定向有3个状态:

302Found   临时移动,未考虑保留

303See Other 不保留,退化成GET  

307Temporary Redirect 保留原方法  

302约等于307

2.面试问题:GET和POST有什么区别?

 根本区别只有一个,就是语义不同。GET代表获取的语义,POST代表的是提交语义。

具体表现上的不同:

1.标准中规定:GET不应该带有请求体;POST可以带有请求体。

2.有请求参数的话,GET请求放在查询字符串URL中,POST请求放在查询字符串或请求体中(form表单)

由于浏览器的实现,URL的长度限制(1000个字符)短于请求体的限制(无限制)

URL一般会记录在日志中,请求体不会记录日志,所以说,POST比FET稍微安全一些。

如果要真正安全,使用HTTP协议。

3.将HTTP方法类比成SQL动作

GET(select)、POST(insert)、PUT(update)、DELETE(delete)——Restful建议

GET、PUT是幂等的;GET无副作用,PUT有副作用(执行不会影响数据)

POST、DELETE不是幂等的

约束限制等级:无副作用>幂等。无副作用一定幂等,但幂等不一样是无副作用的。

    比如,select*from 表  where name= 'x';  今天、明天、永远执行下去,得到的结果都是一致的,这就是幂等的。反之,同样的语句,第一次成功,以后可能失败,就是不幂等的。


常见场景下的代码片段:

1.输出文本响应

 2.读取请求参数

 3.重定向redirect  (不保留方法的临时重定向  302/307) 

HTTP协议: 30X + Location 

redirect             vs          forword(...)

HTTP协议                     Servlet内部 


3.尝试写一个成绩单

在代码中录入了成绩,然后打印

@WebServlet("/demo-1")
public class Demo1 extends HttpServlet {
    //首先把数据准备好
    private final HashMap<String,Integer> 成绩单 = new LinkedHashMap<>();
    //linkedHashMap元素顺序与插入顺序保持严格一致
    // hashMap的元素保存顺序是随机的
    public void init() throws ServletException{
        成绩单.put("门门",99);
        成绩单.put("聪聪",88);
        成绩单.put("毛毛",78);
        成绩单.put("果果",80);
        成绩单.put("小平",60);
        //我只要直接在这里添加,就可以显示出来
        成绩单.put("嘻嘻",74);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        //我们要输出完整的成绩单
        writer.println("<!DOCTYPE html>");
        writer.println("<html lang='zh-hans'>");
        writer.println("<head>");
        writer.println("   <meta charset='utf-8'>");
        writer.println("   <title>成绩单</title>");
        writer.println("</head>");
        writer.println("<body>");
        writer.println("   <table border='1'>");
        writer.println("        <tbody>");

        //这里要遍历成绩单

        for (Map.Entry<String, Integer> entry : 成绩单.entrySet()) {
            String name = entry.getKey();
            int grade = entry.getValue();
            writer.println("<tr>");
            writer.printf("<td>%s</td> <td>%d</td> ",name,grade);
            writer.println("</tr>");
        }
        writer.println("        </tbody>");

        writer.println("</table>");
//        writer.println("/<tbody>");
//        writer.println("/<body>");
//        writer.println("/<html>");

    }
}

具体拆分:

代码展示:

ListServlet类:

@WebServlet("/list.html")
//对web链接的引用可以具体到html/css文件的具体格式
public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        //我们要输出完整的成绩单
        writer.println("<!DOCTYPE html>");
        writer.println("<html lang='zh-hans'>");
        writer.println("<head>");
        writer.println("   <meta charset='utf-8'>");
        writer.println("   <title>成绩单</title>");
        writer.println("</head>");
        writer.println("<body>");
        writer.println("   <table border='1'>");
        writer.println("        <tbody>");

        //这里要遍历成绩单

        for (Map.Entry<String, Integer> entry : GradeRepository.getInstance().map.entrySet()) {
            String name = entry.getKey();
            int grade = entry.getValue();
            writer.println("<tr>");
            writer.printf("<td>%s</td> <td>%d</td> ",name,grade);
            writer.println("</tr>");
        }
        writer.println("        </tbody>");

        writer.println("</table>");
    }
}

SaveServlet类:

@WebServlet("/save")
public class SaveServlet extends HttpServlet {
    public static HashMap<String,Integer> map = new HashMap<>();
    //这里必须定义成静态属性static,静态属性只有一份

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //需要做三件事
        //1.读取
        //2.保存
        //3.重定向
        
        //通过Post将数据保存
        req.setCharacterEncoding("utf-8");
        String name = req.getParameter("name");//获取参数
        String grade = req.getParameter("grade");
        //姓名和成绩不能为空
        if(name == null || name.trim().isEmpty()){
            System.out.println("姓名不能为空哟~");
            //走到这里,用户不按照操作,我们直接返回
            return;
        }
        if(grade == null || name.trim().isEmpty()){
            System.out.println("成绩不能为空哟~");
            return;
        }
                int g =0;
        try {
            g = Integer.parseInt(grade);
        }catch (NumberFormatException exc){
            System.out.println("输入的成绩不是数字哦~");
        }
        //2.保存: 保证数据是同一份数据
        //上一次我们使用了静态资源,这次使用一个新的方法
        GradeRepository.getInstance().map.put(name,g);

        //3.重定向
        resp.sendRedirect("/list.html");
    }
}

GradeRepository类:

  //成绩仓库
    //要让两个类实现资源共享,使用单例模式
public class GradeRepository {

    public final HashMap<String,Integer> map = new HashMap<>();
    //这里必须是public  ,否则save中无法访问

    private  final static GradeRepository repository = new GradeRepository();
    //这里必须static 才能保证同一份数据   单例模式
    protected static GradeRepository getInstance(){
        return repository;
    }
}

 record.html:

<body>
      <form method="post" action="/save">
          <input type="text" name="name">
          <input type="text" name="grade">
          <button>提交</button>
      </form>
</body>

 成绩录入功能{提交页面/列表页面} {/record.html      /save     /list.html}

红色资源是用户可以直接访问的

1.错误处理(错误排查)

1.这里列举我遇到的:路径缺少404错误

第一次我写的是/list,我以为会自动生成html文件,在浏览器中显示了404错误。

正确的写法:资源路径的引用应该具体到具体文件,比如js,或者html,这样才能查找到

2.开发者工具长期打开

看元素面板的内容是否正确,确保浏览器中的代码和IDEA中的代码是否一致

源码面板

网络面板

 查看当前资源的状态,具体可能出现什么错误

控制台

3.具体每层可能出现的问题

网络层(网络不通)

传输层(TCP链接无法建立:Tomcat没有启动、防火墙)

应用层(状态码)

Tomcat启动失败: 1.端口被占用  2.Servlet的URL问题  (开启了多个 或者 没有以/开头)

4.  500错误

@WebServlet("/will-500")
public class ThrowException extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        req.getParameter("username");
        req.getParameter("password");

        //int n = 1/0;
        //除零异常,一定会出现错误

        try{
            int n = 1/0;
        }catch(ArithmeticException e){
            throw new RuntimeException(e);
            //由于一个算法异常导致了运行时异常
        }
    }
}

(1)Tomcat内部的问题

(2)代码中出现了异常(观察异常发生的调用栈,找到代码出错的位置)

也可能是代码拼写错误,比如我遇到的,将数据库grades写成了grade,就一直报错

以上展示是专门写的500错误,我个人遇到的500错误,空指针异常,原因是DBUtil没有和数据库建议连接,我只写了return null。 

5.辅助方法

添加日志(添加打印)或者多去调试 

6.理清我们有多少资源,资源支持方法是什么,资源的Path是什么,资源的职责是什么,资源的关系

2.数据的持久化存储(文件 -> MySQL)

我们已经启动过Tomcat,并且录入了一定的数据。当我们再次重启Tomcat时,成绩单中的数据为空,这是为什么?

数据时保存在GradeRepository的hashMap中,重启Tomcat,就是上一个被暂停,开启了一个新的tomcat,这就是两个tomcat进程,进程和进程之间的数据是隔离的,所以新进程拿不到上一个进程的数据。

1.JDBC

需要引入一个jdbc-mysql的依赖

DataSource对象   Connection对象    PrepareStatement对象    executeUpdate/executeQuery

ResultSet对象    while(rs.next()){...//一行行的去读取}

关联数据库,还需要在pom.xml文件进行修改

显示如下,就说明导入成功

3.拼接HTML比较麻烦(1.模板   2.前后端分离)

主要是针对人的视角

前端通过ajax技术,从后端(通过HTTP协议)读取数据(数据格式JSON为主)

成绩录入——具体实现思路:

 类越来越多,为啥需要这么多类?

model包下是承载数据的具体的类,有时候也命名为DataObject DO

写这么多包,是为了方便程序员的阅读

1.承载数据的对象——属性  ( 鱼香肉丝)

   序列化:JSON、equals、comparable、hashCode

2.承载流程的对象——方法     (前台、服务员、厨师)

单例的


在不同文件格式下,相互转换用到的方法:

<think>好的,我现在需要帮助用户解决在JSP页面中遇到的org.apache.jasper.JasperException异常。首先,我需要回忆一下这个异常通常是由什么原因引起的,然后根据用户提供的引用内容来具体分析可能的解决方案。 根据用户提供的引用内容,特别是引用[2]、[3]、[4]中的信息,常见的导致这个异常的原因有几个方面: 1. **JSP标签库配置错误**:引用[3]提到,当使用Tomcat 11时,需要将JSTL标签库的URI从`java.sun.com/jsp/jstl/core`改为`jakarta.tags.core`,因为Tomcat 11支持的是Jakarta EE而不是Java EE。用户可能在JSP页面中使用了旧的javax包名,而Tomcat 11无法识别,导致编译错误。 2. **JSP Servlet配置问题**:引用[2]指出,修改Tomcat的web.xml文件中JspServlet的配置,特别是development参数设置为true,可以让Tomcat在修改JSP后自动重新编译,避免缓存问题。 3. **包名安全性问题**:引用[4]提到,如果包名使用了被禁止的名称(如javajavax、org.apache等),会抛出SecurityException,进而导致JasperException。需要检查项目中是否有自定义的类使用了这些禁止的包名。 4. **JSP语法错误**:虽然用户没有直接提到,但JSP页面中的语法错误(如标签未正确闭合、EL表达式错误等)也可能导致编译失败。需要检查第17行的代码是否存在这类问题。 接下来,我需要逐步分析可能的解决步骤: **第一步:检查JSP页面第17行的代码** 用户提到异常出现在/showStudent.jsp的第17行。应该首先查看这一行的代码是否存在明显的语法错误,比如未闭合的标签、错误的EL表达式或标签库引用错误。例如,引用[3]中的情况,第17行可能涉及JSTL标签的使用,需要确认URI是否正确。 **第二步:验证JSTL标签库的URI** 如果第17行使用了JSTL标签,比如`<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>`,在Tomcat 11下需要更改为`<%@ taglib prefix="c" uri="jakarta.tags.core" %>`。同时,确保项目依赖的是Jakarta的JSTL实现库,如jakarta.servlet.jsp.jstl-apijakarta.servlet.jsp.jstl。 **第三步:检查web.xml中的JspServlet配置** 根据引用[2],找到Tomcat的web.xml(位于conf目录下),检查JspServlet的配置,确保development设置为true,这样可以启用动态重新编译,避免缓存导致的旧版本问题。 **第四步:检查自定义类的包名** 如果项目中有自定义的Java类,特别是被JSP页面引用的类,需要确认包名是否符合规范,没有使用禁止的包名如javajavax、org.apache等。如引用[4]所述,这会导致SecurityException,进而引发JasperException。 **第五步:清理Tomcat工作目录** 有时候旧的编译文件可能导致问题,清理Tomcat的work目录,让Tomcat重新编译所有JSP页面。 **第六步:查看详细错误日志** Tomcat的日志文件(如catalina.out或localhost.log)通常会提供更详细的错误信息,包括具体的编译错误原因。通过查看日志,可以更快定位问题所在。 **可能的其他原因**: - **缺少依赖库**:项目可能缺少JSTL库或Servlet API的依赖。需要检查pom.xml或lib目录,确保相关依赖存在且版本兼容Tomcat 11。 - **JDK版本不兼容**:使用过高或过低的JDK版本可能导致编译问题,确认Tomcat项目使用的JDK版本一致。 - **文件权限问题**:Tomcat没有权限写入工作目录,导致无法生成编译后的类文件,检查目录权限设置。 **验证步骤**: 1. 修改JSTL标签的URI为Jakarta版本,更新依赖。 2. 清理Tomcat工作目录并重启服务器。 3. 检查第17行代码是否有语法错误。 4. 查看日志确认错误是否解决。 如果以上步骤仍无法解决问题,可能需要进一步分析日志中的具体错误信息,例如是否存在其他编译错误,如类型不匹配、方法不存在等。</think>### 解决JSP页面中org.apache.jasper.JasperException异常的步骤 #### 1. **检查JSP页面第17行的代码语法** - 定位到`/showStudent.jsp`的第17行,检查是否存在以下问题: - **未闭合的标签**(如`<c:if>`未闭合)。 - **错误的EL表达式**(如`${user.name`缺少闭合`}`)。 - **标签库引用错误**(如JSTL标签URI未更新为Jakarta版本)。 - **示例修正**: ```jsp <%-- 错误示例(Tomcat 11不兼容) --%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- 修正后(使用Jakarta URI) --%> <%@ taglib prefix="c" uri="jakarta.tags.core" %> ``` #### 2. **更新JSTL依赖标签库URI** - **依赖配置**(Maven项目): ```xml <dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>2.0.0</version> </dependency> ``` - **标签库修正**:确保所有JSTL标签的URI指向`jakarta.tags.core`[^3]。 #### 3. **配置Tomcat的JspServlet以启用动态编译** - 打开`Tomcat安装目录/conf/web.xml`,找到`JspServlet`配置,添加`development`参数: ```xml <servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> <init-param> <param-name>development</param-name> <param-value>true</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet> ``` 重启Tomcat使配置生效[^2]。 #### 4. **检查自定义类的包名安全性** - 确保项目中自定义的类**未使用禁止的包名**(如`java.`、`javax.`、`org.apache.`等)。 - **错误示例**: ```java package org.apache.myapp; // 触发SecurityException ``` - **修正为**: ```java package com.mycompany.myapp; // 合法包名 ``` #### 5. **清理Tomcat工作目录并重启服务** - 删除`Tomcat安装目录/work/Catalina/localhost/`下的项目缓存文件。 - 重启Tomcat以强制重新编译JSP。 #### 6. **查看Tomcat日志定位具体错误** - 打开`Tomcat安装目录/logs/catalina.out`,搜索`org.apache.jasper.JasperException`,根据日志中的**具体错误描述**(如缺失类、语法错误)进一步修复。 --- ### 其他常见原因及解决方案 - **缺失JAR依赖**: 确保`WEB-INF/lib`目录包含`jakarta.servlet.jsp.jstl-api-2.0.0.jar``jakarta.servlet.jsp.jstl-2.0.0.jar`。 - **JDK版本不匹配**: Tomcat 11需要**JDK 11或更高版本**,检查环境变量`JAVA_HOME`是否指向兼容的JDK。 --- ### 总结流程图 ```plaintext 开始 │ ├─ 1. 检查/showStudent.jsp第17行语法 │ ├─ 修正标签闭合 → 问题解决? │ └─ 更新JSTL URI → 问题解决? │ ├─ 2. 配置Tomcat的JspServlet开发模式 │ └─ 重启Tomcat → 问题解决? │ ├─ 3. 检查自定义类包名 │ └─ 修改包名 → 问题解决? │ ├─ 4. 清理Tomcat工作目录 │ └─ 重启Tomcat → 问题解决? │ └─ 5. 查看Tomcat日志 └─ 根据日志修复具体错误 → 问题解决? ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值