了解Servlet的概念与使用方式

什么是Maven:

Maven是一个构建工具,帮助程序猿来构建,测试,打包一个项目;

在工作中,因为某个项目比较庞大,并不是在IDE中点一下运行就直接运行的,一些项目对哪些文件先编译后编译有特殊的要求等等,而Maven就是帮助我们组织整个庞大项目的,与此类似的还有Ant(一个老牌构建工具),Gradle(主要用于安卓生态)

引入Servlet依赖:

Servlet是tomcat的一组api,在开发阶段并不在标准库内,需要引入依赖,可以从Maven中央仓库下载,注意依赖库的版本要对应tomcat的版本,如tomcat 8.5版本对应Servlet3.1.0的版本

创建目录:

这里的目录创建一定要准确,和下图一模一样(当然你也可以自定义配置)

web.xml模板:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

开始写代码:

以hello world为例:

要创建一个继承了HttpServlet的类,然后重写doGet方法,如果HttpServlet没有代码提示,可以刷新一下,或者尝试清除缓存(File-Invalidate caches),如果仍然不行,说明可能依赖库没有设置好

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //这是调用父类的doGet,其会触发一个发送405错误
        //super.doGet(req, resp);
        //这个是打印在服务器的控制台中,客户端是看不到的
        System.out.println("hello,world");
        //这个是在resp的body中写入hello,world,然后这个响应返回给浏览器后,会显示在浏览器的页面上
        //resp.getWriter()是获取resp内部的Writer对象
        resp.getWriter().write("hello,world");
    }
}

 

如何运行

打包与部署:

当前写的程序不能直接独立运行,必须部署到tomcat上才能运行

部署的前提就是打包:

在Java中使用的压缩包是.jar和.war.其中jar是普通Java程序打成的jar,而war是部署给tomcat打成的war,是tomcat专属的格式,其内部有一些特定的目录结构和文件,比如web.xml等,后续tomcat就要识别这些内容,来加载webapp

打包的过程:

1.检查代码中是否存在依赖,检查依赖是否下载好

2.将代码进行编译,生成一对.class文件

3.把这些.class文件以及web.xml按照一定的格式进行打包

如果打.war包失败,可能是BOM导致的:java: 非法字符: ‘\ufeff‘解决方法_非法字符: '\ufeff_云边的快乐猫的博客-CSDN博客

检验程序:

所谓doGet,就是在触发一个get请求后触发的方法

启动tomcat后,在同一个电脑打开浏览器输入127.0.0.1:8080/hello_servlet/hello就可以看到效果(输入URL就会触发GET方法)

其中hello_servlet这被称作Context Path/Application Path,标志了这个webapp(也就是这个webapp的目录名/war包名)

hello称作Servlet Path,标识了当前请求要调用哪个Servlet类的doGet

抓个包看看:

将打包与部署简化为一键式完成:

每次修改代码都要重新打包,重新部署,比较麻烦,我们可以一个叫smart tomcat的插件实现简化,如果你使用的是专业版的IDEA,其内置了Tomcat Server,可以代替这个插件的功能,但是tomcat Server使用麻烦,还是建议使用smart tomcat

使用smart tomcat和普通的将war包拷贝的webapps中这两种运行方式存在本质区别,smart tomcat其实是tomcat的另一种运行方式,其通过特定的参数来指定tomcat加载某个特定目录中的webapp,因此使用smart tomcat的时候不会存在打包也不会存在拷贝,所以打开webapps会发现没有什么变化

使用smart tomcat一般是在开发和调试阶段,如果是部署到生产环境,还得是需要打包拷贝

如何使用 smart tomcat:

使用tomcat时常出现的一些问题:

404:

1.请求路径写的不对,Context Path 或者 Servlet Path写的不对

2.war包没有被正确加载,比如web.xml写的不对,或者两个Servlet中的Servlet Path相同,也会导致不能正确加载,如果未能加载成功,日志会有提示

405:

1.发送请求的方法和代码不匹配,比如代码写的是doPost,但发送的请求是GET

2.没有注释掉或者删掉 super.XXX 比如super.doGet

500:

服务器代码抛出异常比如:

空白页面:

服务器没有返回任何数据

无法访问此网站:

没有启动tomcat

让浏览器识别编码格式:

如果不设置编码格式,如果在body中写一个中文,可能在浏览器中是乱码,在Java中String类型是utf8编码的,而浏览器的编码格式是默认和操作系统一样的,如果是win10简体中文版,其默认的编码是gbk,编码格式对不上就会出现乱码

需要注意的是在同一个响应中,不要同时使用两种输出流,会出现一些不可预料的错误

三组重要API:

HttpServlet:

方法名称

调用时机

init

在HttpServlet实例化后被调用一次

destroy

在 HttpServlet 实例不再使⽤的时候调⽤⼀次

service

收到 HTTP 请求的时候调⽤

doGet

收到 GET 请求的时候调⽤(由 service ⽅法调⽤)

doPost

收到 POST 请求的时候调⽤(由 service ⽅法调⽤)

doPut/doDelete/doOptions/....

收到其他请求的时候调⽤(由 service ⽅法调⽤)

init:

HttpServlet被实例化之后,会调用一次,使用这个方法是要做一些初始化相关的工作。在首次收到请求的时候,HttpServlet就会被实例化(即使是405也会触发init),比如输入URL后,就会触发HelloServlet的doGet,而在调用doGet前会先调用init

注意,init只执行一次,后续则不再执行:

destroy:

destroy是在webapp被卸载(销毁)之前执行一次,用于做一些结束之前的工作

关闭服务器有两种方式:

1.直接杀死进程(不能触发destroy)

2.使用8005管理端口停止服务器,此时destroy能执行

但是在日常工作中,大多是都是使用高效率的直接杀死进程的方式停止服务器,因此不建议使用destroy

service:

每次收到路径匹配的请求,都会执行,doGet/doPost....等方法都是由service调用的

HttpServletRequest:

tomcat解析一个http请求后经过解析,就换产出一个这个类的对象,其中包含了诸多http请求的属性

方法

描述

String getProtocol()

返回请求协议的名称和版本。

String getMethod()

返回请求的 HTTP ⽅法的名称,例如,GET、POST 或 PUT。

String getRequestURI()

从协议名称直到 HTTP 请求的第⼀⾏的查询字符串中,返回该请求的 URL 的⼀部分。

URI是唯一资源标识符;URL是唯一资源定位符,两者概念非常接近,以至于有时候混着用

String getContextPath()

返回指示请求上下⽂的请求 URI 部分。

String getQueryString()

返回包含在路径后的请求 URL 中的查询字符串。

Enumeration getParameterNames()

返回⼀个 String 对象的枚举,包含在该请求中包含的参数的名称

String getParameter(String name)

以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。

String[] getParameterValues(String name)

返回⼀个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。

Enumeration getHeaderNames()

返回⼀个枚举,包含在该请求中包含的所有的头名。

String getHeader(String name)

以字符串形式返回指定的请求头的值

String getCharacterEncoding()

返回请求主体中使⽤的字符编码的名称

String getContentType()

返回请求主体的 MIME 类型,如果不知道类型则返回 null。

int getContentLength()

以字节为单位返回请求主体的⻓度,并提供输⼊流,或者如果⻓度未知则返回 -1。

InputStream getInputStream()

⽤于读取请求的 body 内容. 返回⼀个InputStream 对象

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/show")
public class showRequest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");
        StringBuilder builder = new StringBuilder();
        builder.append(req.getProtocol());//获取请求协议的名称与版本
        builder.append("<br>");
        builder.append(req.getMethod());//获取请求方法
        builder.append("<br>");
        builder.append(req.getRequestURI());//获取URI
        builder.append("<br>");
        builder.append(req.getQueryString());//获取query String
        builder.append("<br>");
        builder.append(req.getContextPath());//获取Context Path
        builder.append("<br><hr>");
        Enumeration<String> names =  req.getHeaderNames();//获取header所有键
        while (names.hasMoreElements()){
            String name = names.nextElement();
            String value = req.getHeader(name);//根据键获取header值
            builder.append(name + " : " + value + "<br>");
        }
        resp.getWriter().write(builder.toString());
    }
}

getParameter(最常用的API之一):

getParameter常用于前后端数据传递的桥梁,后端常用三种方式进行数据获取:

1.通过 query String:

query string中的键值对都是程序猿自定义的,比如前后端约定通过query string传递 userName和passWord:

等tomcat收到一个请求后,其会将query string中的键值对存放在请求中

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/getParameter")
public class GetParameter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");
        if (userName == null){
            System.out.println("query string中没有userName");
        }
        System.out.println(userName);
        String passWord = req.getParameter("passWord");
        if (passWord == null){
            System.out.println("query string中没有password");
        }
        System.out.println(passWord);
        resp.getWriter().write("finally");
    }
}

因为有的浏览器或者http服务器对中文或者特殊字符的支持性不好,需要注意的是如果在URL中存在中文或者其他特殊字符,需要进行Urlencode编码,将编好的码替换中文或者特殊字符,如"大"的编码就是%E5%A4%A7

一般前端负责编码,后端负责解码

注意这种机制只针对URL/URI

UrlEncode编码和UrlDecode解码-在线URL编码解码工具

 2.通过 body(from表单):
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/getParameter")
public class GetParameter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");
        if (userName == null){
            System.out.println("query string中没有userName");
        }
        System.out.println(userName);
        String passWord = req.getParameter("passWord");
        if (passWord == null){
            System.out.println("query string中没有password");
        }
        System.out.println(passWord);
        resp.getWriter().write("finally");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");
        if (userName == null){
            System.out.println("body中没有userName");
        }
        System.out.println(userName);
        String passWord = req.getParameter("passWord");
        if (passWord == null){
            System.out.println("body中没有password");
        }
        System.out.println(passWord);
        resp.getWriter().write("finally");
    }
}

form不好构造,这里用postman直接构造请求:

如果在请求body中存在中文或者特殊字符,需要在相应的doXXX方法内设置认为请求的编码格式,不然可能因为中文或者特殊字符出现乱码:

req.setCharacterEncoding("utf8");

注意这里的设置认为请求的编码格式只针对请求体,也就是body,这和URL的编码节码并不冲突

3.通过body(json):

这是日常开发中最常用的方式

Servlet内部没有json的解析功能,所以这里需要引入第三方库,这里使用Jackson,因为jackson是spring官方指定的产品

Maven Repository: com.fasterxml.jackson.core » jackson-databind » 2.15.0 (mvnrepository.com)

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

class User{
    //这里的属性名字要和json中键值对的键一样
    public String userName;
    public String passWord;
}

@WebServlet("/json")
public class JsonServlet extends HttpServlet {
    private ObjectMapper mapper = new ObjectMapper();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //这里是通过获取请求的输入流和类对象,通过反射创建一个User对象,将json中的value写到该对象的属性中
        User user = mapper.readValue(req.getInputStream(),User.class);
        System.out.println(user.userName);
        System.out.println(user.passWord);
        resp.getWriter().write("finally");
    }
}

json数据格式整体采用的是utf8和Unicode编码格式,utf8包含了Unicode能标识的所有数据,所以说这里不会存在前后端数据交互时产生的乱码问题,这也是json是最好的跨语言跨平台的数据格式之一的原因

需要注意的一点是,如果后端设置了application/json;charset=utf8的格式,但没有在resp中传递任何数据,前端的ajax中的success方法可能难以执行

HttpServletRespone:

方法

描述

void setStatus(int sc)

为该响应设置状态码。

void setHeader(String name, Stringvalue)

设置⼀个带有给定的名称和值的 header. 如果name 已经存在, 则覆盖旧的值

void addHeader(String name, Stringvalue)

添加⼀个带有给定的名称和值的 header. 如果name 已经存在, 不覆盖旧的值, 并列添加新的键值对

void setContentType(String type)

设置被发送到客户端的响应的内容类型

void setCharacterEncoding(Stringcharset)

设置被发送到客户端的响应的字符编码(MIME字符集)例如,UTF-8

void sendRedirect(String location)

使⽤指定的重定向位置 URL 发送临时重定向响应到客户端。

PrintWriter getWriter()

⽤于往 body 中写⼊⽂本格式数据.

OutputStream getOutputStream()

⽤于往 body 中写⼊⼆进制格式数据

这是对setStatus的应用

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/status")
public class StatusServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(404);
        resp.setContentType("text/html;charset = utf8");
        resp.getWriter().write("这是一个404相应");
    }
}

 


 利用setHeader对refresh进行设置,让其每过一秒就刷新一下界面

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("refresh","1");
        resp.setContentType("text/html;charset = utf8");
        resp.getWriter().write("<h1> time = " + System.currentTimeMillis() + "</h1>");
    }
}


 对重定向的应用:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("location","https://www.sogou.com");
        resp.setStatus(302);
    }
}


目录

什么是Maven:

引入Servlet依赖:

创建目录:

开始写代码:

如何运行

检验程序:

将打包与部署简化为一键式完成:

如何使用 smart tomcat:

使用tomcat时常出现的一些问题:

404:

405:

500:

空白页面:

无法访问此网站:

让浏览器识别编码格式:

三组重要API:

HttpServlet:

init:

destroy:

service:

HttpServletRequest:

getParameter(最常用的API之一):

1.通过 query String:

 2.通过 body(from表单):

3.通过body(json):

HttpServletRespone:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值