Servlet 进阶篇

Servlet进阶

Servlet3.0注解配置

注解配置的使用

我们删除之前的web.xml的配置文件,在我们要配置URL路径的Servlet类上添加@WebServlet()注解,括号里面传入我们要处理的请求的URL路径,以/开头

@WebServlet("/hello")
public class ServletDemo1 implements Servlet {
    ...
}

原来的xml,我们看到别名是冗余的只是为了识别,一个servlet就8行,阅读性很差。

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.kaikeba.course06.ServletDemo1</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

URL路径

我们看一下@WebServlet注解的源码,我们知道如果注解中只有一个属性,那么默认就是value()属性。其中value()属性指的就是urlPatterns(),我们看到其实传入的是一个数组,所以我们的Servlet3.0的注解配置支持一个Servlet处理多个请求。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
    String name() default "";

    String[] value() default {};

    String[] urlPatterns() default {};

    int loadOnStartup() default -1;

    WebInitParam[] initParams() default {};

    boolean asyncSupported() default false;

    String smallIcon() default "";

    String largeIcon() default "";

    String description() default "";

    String displayName() default "";
}

如果要指定load-on-startup,我么可添加该参数,我们看到默认是-1,和web.xml的文件配置是一样的。

@WebServlet(urlPatterns = "/hello",loadOnStartup = 1)
public class ServletDemo1 implements Servlet {
    ...
}

URL的使用方式

  1. 普通方式
  • /hello:处理URL路径为/hello的请求
  • ``/user/hello`:处理URL路径为/hello的请求

很好理解,我们的URL和请求一一对应,不区分大小写。

  1. 添加通配符
  • /*:处理所有请求
  • /user/*:处理第一层为hello的所有请求
  • *.do:处理任何以.do结尾的请求

注意事项:

通配符的优先级是非常低的,所以默认情况下。用户发来一个请求,如果我们不是使用通配符的URL也能处理请求,则通配符是不生效的,但是如果没有一个Servlet可以处理一个请求,则通配符*才会生效的。

特殊情况演示:

请求:/hello

执行顺序:/hello/* > /hello > /*

请求:/user/hello

执行顺序:/user/hello/* > /user/hello > /user/* > /* >

我们如果定义了多级目录,比如/a/b 就不要使用/a这样的请求了!

  1. 错误方式
  • /*.do

image-20200922180014744

  • /*/*

    这种方式会失去匹配功能,也根据浏览器而异,一般情况下,该URL什么都无法接收。

  • /he*

image-20200922180042088

  1. 特殊方式
  • /

    在不同的浏览器对/请求处理不同。谷歌浏览器不会将/作为请求,而在火狐浏览器的//*有相同的作用,但是如果处理//*的Servlet都存在,则优先执行/*,所以我们尽量减少

HttpServlet

HttpServlet是GenericServlet的实现类,GenericServlet是Servlet接口的空实现抽象类,HttpServlet是我么最常用的Servlet了。

image-20200922182024154

常量

HttpServlt定义了8个常量,对应浏览器的7种请求(少了一个HEAD请求)。

public abstract class HttpServlet extends GenericServlet {

    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";
    ......
}

处理HTTP请求

源码比较长,简单看一下:

  • 使用request.getMethod()方法获取请求类型,值是“POST”,"GET"这样的大写。
  • 使用一堆if – else if 来判断是哪种请求,然后执行对应方法,比如POST请求对应doPost()方法。
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);
    }
}

一般操作

我们只要复写对应的doGet(),doPost()方法即可,Servlet收到请求时,会根据requset.getMethod()获得请求类型,我们不要去干重写service方法的迷惑操作。

@WebServlet("/service")
public class HttpServletDemo2 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get方法");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("post方法");
    }
}

中文乱码

Http之间传输数据可能会出现乱码问题,这需要我们统一编码:

接收用户数据乱码问题:

String username=request.getParameter("username");
//转码
username = new String(username.getBytes("ISO-8859-1") , "UTF-8");
System.out.println("userName="+username+"==password="+password);

发送数据给用户乱码问题:

//告诉服务器用编码来解析什么来解析
response.setCharacterEncoding("UTF-8");
//告诉客户端用什么编码
response.setHeader("content-type", "text/html;charset=UTF-8");

或者使用这个,一个顶两

response.setContentType("text/html;charset=UTF-8")
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值