JavaWeb-Servlet(下)

目录

1 Http协议

1.1 概述

1.2 get请求和post请求

2 HttpServlet源码分析

3 关于web站点的欢迎页面

4 HttpServletRequest接口详解

4.1 概述

4.2 HttpServletRequest常用方法

4.3 请求域对象

4.4 HttpServletRequest其它常用的方法

5 使用纯Servlet做一个单表的增删改查

6 转发和重定向

7 Servlet注解,简化配置

9 使用模板方法设计模式优化oa项目

10 详细代码


1 Http协议

1.1 概述

好消息好消息,我们今后不用GenericServlet了,改用HttpServlet了,好像又白学了。。。

并没有白学,它是继承GenericServlet的,很多相同的地方,因为我们是B/S架构的系统,这种系统是基于HTTP超文本传输协议的,HttpServlet处理HTTP协议更便捷。

在学习HttpServlet之前我们先了解一下HTTP协议

先写一些代码协助我们理解:

代码主要就是写一个html页面,其中使用到form标签,并且提交使用get和post两种方式,响应到servlet并输出servlet中的信息。




    
    get and post


get方法提交

username
password

post方法提交

username
password

HTTP协议包括请求协议和响应协议

HTTP请求协议:

请求协议是浏览器向服务器发送请求,请求协议包含四部分:请求行、请求头、空白行、请求体

根据我们写的代码可以得到HTTP响应协议具体报文,得到报文的方法是在浏览器按F12键,network中记录着报文内容:

post请求:

​​​​POST /servlet04/postServlet HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 28
Content-Type: application/x-www-form-urlencoded
Cookie: Idea-35e4271=01328648-8b36-4624-b567-815b69706ef0
Host: localhost:8080
Origin: http://localhost:8080
Referer: http://localhost:8080/servlet04/index.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"

username: wangwu
password: 123

然后后面的不想学了。。再见

HTTP响应协议:

响应协议是服务器向浏览器发送响应,响应协议包含四部分:状态行、响应头、空白行、响应体

JavaWeb-Servlet(下)_第1张图片

其中状态行中的200是状态码(HTTP协议中规定的响应状态号,不同响应结果对应不同号码),200表示响应成功,正常结束;404表示访问资源不存在,通常是路径写错了,或者服务器中对应的资源没有启动成功,404错误是前端错误;405表示前端发送的请求与后端的处理方式不一致发生的,比如前端是get而后端是post;500表示服务器端的程序出现了异常,一般是服务器端的错误;以4开始一般是浏览器错误,以5开始一般是服务器错误。

1.2 get请求和post请求

怎么向服务器发送GET请求,怎么向服务器发送POST请求?

到目前为止,只有一种情况可以发POST请求:使用form表单属性method=“post”。其它所有情况都是get请求。

get请求和post请求区别?

  • get请求发送数据,数据会挂在URI的后面,并且在URI后面加了一个“?”;post请求发送数据的时候在请求体中发送,不会显示到浏览器地址上。
  • get请求只能发送普通的字符串,并且长度有限制,无法发送大量数据
  • post请求可以发送任何类型的数据,包括字符串声音视频图片,可以发送大量数据没有限制
  • W3C是这样说的:get请求比较适合从服务器端获取数据;post请求比较适合向服务器传送数据。
  • get请求是安全的,为什么?因为get请求只是为了从服务器上获取数据,不会对服务器造成威胁(get本身是安全的,只是要用对地方)。
  • post请求是危险的,为什么?因为post请求是向服务器提交数据,可能对服务器造成威胁。
  • get请求支持缓存,任何一个get请求最终的响应结果都会被浏览器缓存起来,在浏览器缓存当中,一个get请求的路径对应一个资源。实际上,是要发送get请求,浏览器做的第一件事就是从本地浏览器缓存中找,找不到才会去服务器上获取。
  • post请求不支持缓存(post是用来修改服务器资源的,没必要缓存)

get和post请求该如何选择?

请求是获取服务器的数据建议使用get,如果是为了向服务器提交数据建议使用post

不管是get还是post请求,发送数据格式一样都是:name=value&name=value

name和value是什么?以form表单为例就是input标签中的name和value

2 HttpServlet源码分析

此处分析只分析之前没遇到的,遇到的基本上在之前都已经分析过了。

HttpServlet中的方法首先还是执行init方法然后是再执行service方法

JavaWeb-Servlet(下)_第2张图片

 这是HttpServlet里的其中一个service方法,Tomcat会先调用这个service方法,因为参数原因,接着把ServletRequest和ServletResponse对象转为HttpServletRequest和HttpServletResponse,都是带Http的,然后再调用另一个service方法(重载的service方法),把转型好的两个对象传入。下面是重载的service方法

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

我们看到首先就调用getMethod方法来获取请求方式,也就是之前学的get或post请求或者其它的。接着判断获取的是什么请求然后执行相应的方法(doPost、doGet等等方法)。也就是说假如我们使用form表单并且使用post请求来提交信息,service方法就会识别到这是post请求也就会执行doPost方法,但是需要我们重写doPost方法,如果我们没有重写这个方法,那么就会执行父类的也就是HttpServlet中的doPost方法,就会报错。但是如果我们直接重写service方法就不会报错,因为重写了service方法就不会调用doPost方法了。假如我们自己重写service方法,就没有错误提示了,所以是不是建议我们不自己重写service呢???

总结一下一个Servlet类的开发步骤:

  • 第一步:编写一个Servlet类,直接继承HttpServlet
  • 第二步:重写doGet或者doPost方法,重写谁自己说了算
  • 第三步:将Servlet类配置到web.xml文件中
  • 第四步:准备前端页面(form表单),form表单中指定请求路径即可

3 关于web站点的欢迎页面

什么是欢迎页面?

设置了欢迎页面,当你访问这个webapp时,没有指定任何“资源路径”,这个时候会默认访问你的欢迎页面。

怎么设置欢迎页面?

  • 第一步:在idea工具的web目录下新建一个文件login.html
  • 第二步:在web.xml进行以下配置,注意:这个路径不需要以“/”开头,并且默认从webapp的根下开始查找,也就是web目录下开始
  •     
            login.html
        
  • 第三步:启动服务器,输入地址:http://localhost:8080/servlet05

但是我们发现当文件命名为index.html的时候不需要配置就可以直接访问,为什么捏?

 这是因为小猫咪已经提前配置好了,实际上有两个地方可以配置

  • 一个就是webapp的内部的web.xml文件中(这属于局部配置)
  • 一个是CTALINA_HOME/conf/web.xml文件中进行配置(这属于全局配置)
  • 注意:局部优先原则(就近原则)

我们打开源码瞅瞅,果然有这样的配置:

JavaWeb-Servlet(下)_第3张图片

当我们自己配置欢迎页面就会默认访问我们配置的,我们不配置就会访问小猫咪配置的index

欢迎页面可以是servlet吗?

当然可以,只要把路径改为servlet的路径即可,下面展示如何配置:

    
        da/w/wf
    

    
        welcomeServlet
        com.itzw.javaweb.servlet.WelcomeServlet
    
    
        welcomeServlet
        /da/w/wf
    

4 HttpServletRequest接口详解

4.1 概述

HttpServletRequest对象中都有什么信息,都包装了什么信息?

  • HttpServletRequest对象是Tomcat服务器创建的。
  • 实际上是用户发送请求数据,遵循了HTTP协议,发送的是HTTP请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,然后Tomcat服务器把这些信息封装到HttpServletRequest对象中,传给javaweb程序员。
  • javaweb程序员面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息了。

request和response对象的生命周期

  • request和response对象,一个是请求对象,一个是响应对象。这两个对象只在当前请求中有效。
  • 一次请求对应一个request
  • 两个请求对应两个request
  • ....

4.2 HttpServletRequest常用方法

HttpServletRequest接口中有哪些常用的方法

Map getParameter()            获取Map
Enumeration getParameterNames()        获取Map集合所有的key
String getParameter(String name)               根据key获取value这个一维数组中的第一个元素
String[] getParameterValues(String name)       根据key获取value

之所以有一个是返回一个value,有一个是返回value数组,是因为有的value不止一个,比如爱好这个key,它可以有多个爱好,而map集合中的key不能重复。但是我们用的最多的还是一个key对应一个value。

演示:

username:
password:
hobby: 抽烟 喝酒 烫头
package com.itzw.javaweb.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

public class RequestTest extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("

注册成功!

"); //获取我提交的信息 //获取所有key Enumeration parameterNames = request.getParameterNames(); while (parameterNames.hasMoreElements()){ String name = parameterNames.nextElement(); System.out.println(name); } //根据key获取value String username = request.getParameter("username"); System.out.println(username); String password = request.getParameter("password"); System.out.println(password); String[] hobbies = request.getParameterValues("hobby"); for (String hobby : hobbies) { System.out.println(hobby); } } }
username
password
hobby
zhangsan
123
smoke
drink
tangtou

4.3 请求域对象

request对象是什么?request对象又称请求域对象

还记得之前学的应用域对象(ServletContext),什么时候会用应用域对象呢?

  • 第一:所有用户共享的数据
  • 第二:这个共享数据量很小,太大影响内存
  • 第三:这个共享的数据很少的修改操作,修改会有线程危险也会影响效率
  • 实际上应用域是将数据放到了缓存(cache)中,减少IO操作提高性能
  • 还记得应用域使用到的三个方法
  • void setAttribute(String name,Object obj);//向域中绑定数据
    Object getAttribute(String name);//从域中根据name获取数据
    void removeAttribute(String name);//将域中绑定的数据移除

请求域对象

  • 请求域对象比应用域对象范围小得多,声明周期短得多,请求域只在一次请求内有效。
  • 一个请求对象request对应一个请求域对象,一次请求结束后,这个请求域就销毁了。
  • 请求域也有这三个方法:
  • void setAttribute(String name,Object obj);//向域中绑定数据
    Object getAttribute(String name);//从域中根据name获取数据
    void removeAttribute(String name);//将域中绑定的数据移除

请求域不是共享的,当我们在一个servlet中存数据,只能在这个servlet中取出数据和删除数据,在另一个servlet中是无法取出数据和删除数据的。

演示效果:

package com.itzw.javaweb.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        Date thisTime = new Date();
        request.setAttribute("nowTime",thisTime);
        /*Object nowTime = request.getAttribute("nowTime");
        out.print("nowTime:" + nowTime);*/
    }
}
package com.itzw.javaweb.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        Object nowTime = request.getAttribute("nowTime");
        out.print("nowTime:" + nowTime);
    }
}

JavaWeb-Servlet(下)_第4张图片

很显然访问BServlet访问不到信息

两个servlet怎么共享数据?

  • 首先,当然可以将数据放到ServletContext应用域中,但是应用域范围太大,占用资源太多,不建议使用。
  • 可以将数据放到request中,然后AServlet转发到BServlet,保证两个Servlet在同一次请求中

使用请求域共享数据具体操作:

  • 第一步:获取请求转发器对象:request.getRequestDispatcher("/b");
  • 第二步:调用forward完成跳转dispatch.forward(request,response);

在AServlet中加入下面代码:

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

这样AServlet中的request就能跳转到BServlet

需要注意的是:路径的规范前面要加“/”,不需要加项目名。同时不仅可以转到Servlet也可以访问别的文件,比如html,此时路径是以根目录也就是web目录开始,也就是说写在web目录下的文件的路径直接写文件名即可。

request.getRequestDispatcher("/test.html").forward(request,response);

还需要注意的是:request对象中两个非常容易混淆的方法

request.getParameter("username");//这是获取用户在浏览器上提交的数据
request.getAttribute("name");//这获取的是请求域当中绑定的数据

4.4 HttpServletRequest其它常用的方法

request.getRemoteAddr();//获取客户端IP地址

request.setCharacterEncoding("UTF-8");

设置请求体字符集,也就是设置post请求在请求体中提交的数据,只能解决post请求的乱码问题,并且是后端输出的乱发问题,前端也就是浏览器输出的内容乱码需要使用response.setContentType("text/html;charset=UTF-8");

get请求:修改CATALINA_HOME/conf/server.xml配置文件

但其实使用tomcat10这些问题都不会存在。

request.getContextPath();获取应用的根路径(/servlet06)
request.getMethod();获取请求方式(GET/POST)
request.getRequestURI();获取请求的URI(/servlet06/testRequest)
request.getServletPath();获取servlet path(testRequest)

5 使用纯Servlet做一个单表的增删改查

使用servlet完成单表【对部门】的增删改查操作(B/S结构)。

实现步骤

第一步:准备一张数据库表

USE db1;
drop table if EXISTS dept;

create table dept(
	deptno int primary key,
	dname varchar(255),
	loc varchar(255)
);

insert into dept(deptno,dname,loc) values(10,'销售部','上海');
insert into dept(deptno,dname,loc) values(20,'研发部','南京');
insert into dept(deptno,dname,loc) values(30,'技术部','苏州');
commit;

select * from dept;

第二步:准备一套HTML页面

应该设计哪些页面呢?

  • 新增页面:add.html
  • 修改页面:edit.html
  • 详情页面:detail.html
  • 欢迎页面:index.html
  • 列表页面:list.html

第三步:分析我们这个系统包括哪些功能?

什么叫做一个功能?

  • 只要这个操作连接数据库了,就表示一个独立功能。

包括哪些功能?

  • 查看部门列表
  • 新增部门
  • 删除部门
  • 查看部门详细信息
  • 跳转到修改页面
  • 修改部门

第四步:在IDEA中搭建开发环境

  • 创建一个webapp
  • 向webapp中添加连接数据库的jar包
  • 自己先写一个JDBC工具类
  • 将HTML页面拷贝到web下

第五步:实现第一个功能--查看部门列表

我们应该怎样实现一个功能呢?可以先从后端一步步往前端写或者从前端一步步往后端写,最好不要想到哪就写哪。

  1. 第一:先创建一个servlet用于查看列表
  2. 第二:修改前端页面的超链接和编写web.xml文件
  3. 第三:在servlet类中的doGet方法中连接数据库,查询所有信息展示在页面。注意:list.html页面中所有的双引号要替换为单引号。因为out.print("");这里有一个双引号,容易冲突。

第六步:查看部门详情

首先想的是用户点击的是什么?用户点击的东西在哪里?因为本次小测试只用了servlet,所以前端的东西都用后端实现,详情也在后端的java小程序中,点击详情是要连接数据库 的,所以这个超连接点击后需要执行一段java代码。

 注意:这个路径需要加项目名(前端路径都要加项目名),项目名可以动态获取。向服务器提交的数据格式:url?name=value&name=value

 编写web.xml文件和一个servlet类重写doGet方法

第七步:删除部门

从前端页面开始,用户点击删除按钮的时候,应该提示用户是否删除,因为删除这个动作是比较危险的,任何系统在进行删除之前都必须提示用户。在前端页面使用JS代码提示用户是否删除。

删除

注意这里的javascript:void(0)表示仍然保留超连接的样子,点击此超链接之后不进行页面的跳转。也就是说我只希望用户点击该超链接的时候执行一段js代码,不进行页面跳转。

function del(dno){
			var ok = window.confirm("亲,删除了不能恢复哦!")
			if (ok){
				document.location.href="/oa/dept/delete?deptno=" + dno;
			}
		}

注意这里的JS代码中的window.confirm就是弹出确认框,点击确认会返回true,点击取消返回false在JS代码中如何发送请求给服务器呢?  使用document.location.href="";或者window.location.href或者去掉href也可以。

以上的代码要写在后端java小程序中,和之前的方式一样。

第八步:新增部门

注意:最后保存成功后,转发到/dept/list的时候会出现405,为什么??因为保存用的是post请求,底层要执行doPost方法,但转发到的list中只有doGet方法。

怎么解决??

  • 第一种:在list中添加doPost方法,在doPost方法中调用doGet,相当于欺骗小猫咪。
  • 第二种:重定向(还没学)。

第九步:跳转到修改页面

第十步:修改部门信息

在写修改部门信息的代码时出现了一个bug,找了半天,接收到的deptno是空的,我第一反应是name写错了,但确实没写错,懵逼了,然后思考了一下,原来是我接收到的信息是input标签传来的,所以name要和input标签中的name写的一样,当时写的name为dno而不是deptno。

完整代码:

6 转发和重定向

在一个web中如何完成资源的跳转,有两种方式:

  • 第一种:转发
  • 第二种:重定向

转发和重定向有什么区别

代码上的区别:

  • 转发
    request.getRequestDispatcher("/b").forward(request,response);
  • 重定向
    response.sendRedirect(request.getContextPath()+"/b");

形式上有什么区别?

  • 转发:一次请求,在浏览器地址栏发送的请求是http://localhost:8080/servlet07/a,最终请求结束后,浏览器地址栏上的地址还是这个没有变化。这就是为什么转发的代码有forword里面传的是request和response,就是当前的request和response传到了另一个servlet,都只是一个请求罢了。
  • 重定向:两次请求,重定向的路径要加项目名,因为response对象蒋政路径响应给了浏览器,浏览器又向服务器发送了一个新的请求:http://localhost:8080/servlet07/b,所以一共发了两次请求,一次是a一次是b。​​​​​​​

转发和重定向的本质区别?

  • 转发:是由web服务器控制的,A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
  • 重定向:是浏览器完成的。

转发和重定向如何选择??

  • 如果上一个Servlet当中向request域当中绑定了数据,希望从下一个Servlet当中把request域里面的数据取出来,使用转发机制。
  • 上下的均使用重定向(重定向使用较多)

转发会存在浏览器刷新问题

此话怎讲呢,因为转发只是一次请求,比如在我们添加数据的时候,添加完数据跳转到一个页面,当我们不断刷新此页面会发现仍然在添加数据,但重定向不会发生这个问题,因为重定向是两次请求,第二次请求已经和添加数据的请求毫无关系。

7 Servlet注解,简化配置

经过之前做的小项目来看,只是一个小小的项目web.xml文件就写了如此多的信息,如果是一个大的项目的话将会非常麻烦,开发效率极低,而且这些配置是很少被修改的,所以这种配置可不可以直接写在java类中呢?当然可以,从servlet3.0版本后就推出了各种servlet基于注解式开发。这样的优点有哪些呢?开发效率高,不需要编写大量的配置信息,直接在java类上使用注解进行标注;web.xml文件变小了。但并不是有了注解就不需要web.xml文件了,有一些需要变化的信息还是需要web.xml文件,一般不会经常修改的建议使用注解,可能会修改的写到配置文件中。

我们的第一个注解

  • 在servlet类上使用:@WebServlet,注解中有哪些属性呢?
  • name属性:用来指定Servlet的名字,等同于
  • urlPatterns属性:用来指定Servlet的映射路径,可以指定多个,等同于
  • loadOnStartUp属性:用来指定在服务器启动阶段是否加载该Servlet,等同于
  • value属性:当注解的属性名是value时,value属性名是可以省略的
  • 注意:并不是将所有属性都写上去,需要啥写啥,并且属性是一个数组的时候,如果数组只有一个元素是可以省略大括号的,所以一般我们写注解都是只写一个value属性就可以了,形式为:WebServlet("/hello"),非常的方便
  • 注意:注解的格式@注解名称(属性名=属性值,属性名=属性值...) 

当我在写注解的时候出现了一个错误,找了半天,原来是注解中的value属性,也就是指定Servlet的路径,前面没加/

9 使用模板方法设计模式优化oa项目

上面解决了配置文件问题,但是现在的oa项目仍然存在一个比较臃肿的问题:一个简单的增删改查就写了6个servlet。如果一个复杂的系统业务,这种方式会导致类爆炸(类的数量太多),可以使用模板方式解决这个问题。

怎么解决类爆炸问题?

以前是一个请求一个Servlet,现在可以这样:一个请求对应一个方法,一个业务对应一个Servlet类。比如处理部门相关业务的对应一个DeptServlet,处理用户相关业务的对应一个UserServlet等等。

步骤:

  • 第一步:创建一个模块,把上个模块中的文件除了servlet类都赋值到这个模块中
  • 第二步:创建一个Servlet类,使用注解将项目用到的路径写在一个注解中
  • 第三步:重写service方法,获取servlet path,使用方法来代替之前的servlet类就可以了。

10 详细代码

经过上面的改造,目前得到的详细代码如下

首先项目目录结构

JavaWeb-Servlet(下)_第5张图片

 工具类DBUtil:

package com.itzw.oa.util;

import java.sql.*;
import java.util.ResourceBundle;

public class DBUtil {
    //静态变量在类加载时执行
    private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");
    private static String driver = bundle.getString("driver");
    private static String url = bundle.getString("url");
    private static String user = bundle.getString("user");
    private static String password = bundle.getString("password");

    static {
        //注册驱动
        //注册驱动执行一次就可以,所以放在静态代码块,类加载时就执行且执行一次
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接对象
     * @return
     * @throws SQLException
     */
    public static Connection getConnection () throws SQLException {
        Connection conn =  DriverManager.getConnection(url, user, password);
        return conn;
    }

    /**
     * 释放资源
     * @param conn
     * @param st
     * @param rs
     */
    public static void close(Connection conn, Statement st, ResultSet rs){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }


    }

}

配置文件jdbc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db1
user=root
password=123456

servlet类DeptServlet:

package com.itzw.oa.web.action;

import com.itzw.oa.util.DBUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@WebServlet({"/dept/list","/dept/detail","/dept/delete","/dept/save","/dept/edit","/dept/modify"})
public class DeptServlet extends HttpServlet {
    //重写service方法
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //获取Servlet path
        String servletPath = request.getServletPath();
        if ("/dept/list".equals(servletPath)){
            doList(request,response);
        }else if ("/dept/detail".equals(servletPath)){
            doDetail(request,response);
        }else if ("/dept/delete".equals(servletPath)){
            doDel(request,response);
        }else if ("/dept/save".equals(servletPath)){
            doSave(request,response);
        }else if ("/dept/edit".equals(servletPath)){
            doEdit(request,response);
        }else if ("/dept/modify".equals(servletPath)){
            doModify(request,response);
        }
    }

    private void doList(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        String contextPath = request.getContextPath();

        out.print("");
        out.print("");
        out.print("	");
        out.print("		");
        out.print("		部门列表");

        out.print("");

        out.print("	");


        out.print("	");
        out.print("		

部门信息

"); out.print("
"); out.print(" "); out.print(" "); out.print(" "); out.print(" "); out.print(" "); out.print(" "); out.print(" "); //连接数据库 try { conn = DBUtil.getConnection(); String sql = "select deptno,dname,loc from dept"; ps = conn.prepareStatement(sql); rs = ps.executeQuery(); int i = 1; while (rs.next()){ //获取部门信息 int deptno = rs.getInt("deptno"); String dname = rs.getString("dname"); out.print(" "); out.print(" "); out.print(" "); out.print(" "); out.print(" "); out.print(" "); } } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(conn,ps,rs); } out.print("
序号部门编号部门名称操作
"+ (i++) + ""+ deptno +""+dname+"删除"); out.print(" 修改"); out.print(" 详情"); out.print("
"); out.print("
"); out.print(" 添加信息"); out.print(" "); out.print(""); } private void doDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; out.print(""); out.print(""); out.print(" "); out.print(" "); out.print(" 详情信息"); out.print(" "); out.print(" "); out.print("

详情信息

"); out.print("
"); //获取前端提交的数据中的name,本次测试其实是在后端编写的html String deptno = request.getParameter("deptno"); //连接数据库 try { conn = DBUtil.getConnection(); String sql = "select deptno,dname,loc from dept where deptno = ?"; ps = conn.prepareStatement(sql); //将收到的name传入到?中也就是SQL语句中 ps.setString(1,deptno); rs = ps.executeQuery(); while (rs.next()){ //获取部门信息 String dname = rs.getString("dname"); String loc = rs.getString("loc"); out.print("部门编号:"+deptno+"
"); out.print("部门名称:"+dname+"
"); out.print("部门位置:"+loc+"
"); } } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(conn,ps,rs); } out.print(" "); out.print(" "); out.print(""); } private void doDel(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); Connection conn = null; PreparedStatement ps = null; //获取前端提交的数据中的name,本次测试其实是在后端编写的html String deptno = request.getParameter("deptno"); int count = 0; //连接数据库 try { conn = DBUtil.getConnection(); //开启事务(自动提交关闭) conn.setAutoCommit(false); String sql = "delete from dept where deptno = ?"; ps = conn.prepareStatement(sql); //将收到的name传入到?中也就是SQL语句中 ps.setString(1,deptno); count = ps.executeUpdate(); //事务提交 conn.commit(); } catch (SQLException e) { //遇到异常要回滚 if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); }finally { DBUtil.close(conn,ps,null); } //判断是否删除成功 if (count == 1){ //删除成功,仍然跳转到部门列表页面,这里使用转发 //request.getRequestDispatcher("/dept/list").forward(request,response); //改成重定向会好一点 response.sendRedirect(request.getContextPath()+"/dept/list"); }else { //删除失败 //request.getRequestDispatcher("/error.html").forward(request,response); response.sendRedirect(request.getContextPath()+"/error.html"); } } private void doSave(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ response.setContentType("text/html"); Connection conn = null; PreparedStatement ps = null; //接收用户输入的信息 String dno = request.getParameter("dno"); String dname = request.getParameter("dname"); String loc = request.getParameter("loc"); int count = 0; try { //获取连接 conn = DBUtil.getConnection(); //开启事务(本次小测试其实没有使用事务的必要) conn.setAutoCommit(false); String sql = "insert into dept(deptno,dname,loc) values (?,?,?)"; ps = conn.prepareStatement(sql); ps.setString(1,dno); ps.setString(2,dname); ps.setString(3,loc); count = ps.executeUpdate(); //提交事务 conn.commit(); } catch (SQLException e) { e.printStackTrace(); }finally { //回滚事务 try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); } DBUtil.close(conn,ps,null); } if (count == 1){ //添加成功 //request.getRequestDispatcher("/dept/list").forward(request,response); response.sendRedirect(request.getContextPath()+"/dept/list"); }else{ //添加失败 //request.getRequestDispatcher("/error.html").forward(request,response); response.sendRedirect(request.getContextPath()+"/error.html"); } } private void doEdit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String contextPath = request.getContextPath(); out.print(" "); out.print(""); out.print(" "); out.print(" "); out.print(" 修改信息"); out.print(" "); out.print(" "); out.print("

修改信息

"); out.print("
"); out.print("
"); //获取部门编号 String deptno = request.getParameter("deptno"); //连接数据库 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); String sql = "select dname,loc from dept where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1,deptno); rs = ps.executeQuery(); if (rs.next()){ String dname = rs.getString("dname"); String loc = rs.getString("loc"); //得到修改页面 out.print(" 部门编号
"); out.print(" 部门名称
"); out.print(" 部门位置
"); } } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(conn,ps,rs); } out.print(" "); out.print("
"); out.print(" "); out.print(""); } private void doModify(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ //解决请求体乱码的问题 request.setCharacterEncoding("UTF-8"); //获取部门信息 String deptno = request.getParameter("dno"); String dname = request.getParameter("dname"); String loc = request.getParameter("loc"); //连接数据库 Connection conn = null; PreparedStatement ps = null; int count = 0; try { conn = DBUtil.getConnection(); String sql = "update dept set dname = ?,loc = ? where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1,dname); ps.setString(2,loc); ps.setString(3,deptno); count = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DBUtil.close(conn,ps,null); } if (count == 1){ //修改成功 //request.getRequestDispatcher("/dept/list").forward(request,response); response.sendRedirect(request.getContextPath()+"/dept/list"); }else{ //修改失败 //request.getRequestDispatcher("/error.html").forward(request,response); response.sendRedirect(request.getContextPath()+"/error.html"); } } }

add.html:



	
		
		新增页面
	
	
		

添加信息


部门编号
部门名称
部门位置

error.html




    
    失败


操作失败,返回

index.html



	
		
		欢迎页面
	
	
		查看部门列表
	

因为使用了注解,所以web.xml文件没有任何配置

结果:

JavaWeb-Servlet(下)_第6张图片

小小总结一波:本次小项目做了挺久,因为只使用了servlet,过程比较繁琐,尤其是遇到前端部分,只能强行将前端代码塞进后端。接着学到了注解,大大提高了开发效率,最后是模板方式,解决了类太多的问题。那么后面就开始学习别的内容来解决前端代码写在后端的问题。

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