Java Web之Servlet

Posted 蜀云泉

tags:

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

 

  什么是Servlet?

 

  Servlet有什么用?

 

 

  Idea写一个Servlet程序

一、新建一个类

我新建了一个HelloServlet类,要继承一个servlet接口 javax.servlet.Servlet,但是你是打不出来的,原因是没有包,看第二步导入包

然后就可以继承接口方法了,在service方法里面写一个输出语句吧

package main.com.vae.servletDemo;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

public class HelloServlet implements javax.servlet.Servlet{
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    public ServletConfig getServletConfig() {
        return null;
    }

    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("许嵩小名许甜甜");
    }

    public String getServletInfo() {
        return null;
    }

    public void destroy() {

    }
}

二、导入servlet的jar包

你的Tomcat的lib文件夹里面有一个servlet的jar包,复制到WEB-INF下的lib文件夹内,如图

三、修改web.xml

打开WEB-INF下的web.xml,加上这几个

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>main.com.vae.servletDemo.HelloServlet</servlet-class>
    </servlet>

    <!--向外暴露该Servlet类的一个资源名称,供外键直接访问,资源名称必须以 / 打头-->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

四、你的webapp的路径,在Tomcat里面修改

如果你不修改Tomcat的server.xml里面的Context标签,那么你的Tomcat打开后出现的是官方的Tomcat猫界面,我们修改了context之后,如下

 

五、重启Tomcat

输入localhost/hello (备注,我的端口号改为80了,你们默认的是8080),查看idea的控制台

 

 

 Servlet的生命周期

 

 

Servlet的请求流程

 ServletConfig接口初始化参数

我写一个类,继承Servlet接口,想在service方法里面写一个判断,判断name是许嵩,就输出是许嵩,否则输出蜀云泉真帅

这个name变量,我如果在类里面写死的话,那么我想改只能改源码。所以写在配置文件web.xml里面

先看看配置文件web.xml

    <servlet>
        <servlet-name>InitParamServlet</servlet-name>
        <servlet-class>main.com.vae.servletDemo.InitParamServlet</servlet-class>
        <init-param>
            <param-name>name</param-name>
            <param-value>许嵩</param-value>
        </init-param>
    </servlet>

    <!--向外暴露该Servlet类的一个资源名称,供外键直接访问,资源名称必须以 / 打头-->
    <servlet-mapping>
        <servlet-name>InitParamServlet</servlet-name>
        <url-pattern>/init</url-pattern>
    </servlet-mapping>

和上面大差不差,只不过多了一个参数的<init-param>,里面是参数名和参数值。再看看类里面怎么获取的

package main.com.vae.servletDemo;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.Enumeration;

public class InitParamServlet implements javax.servlet.Servlet{

    private ServletConfig config;
    public void init(ServletConfig servletConfig) throws ServletException {
        config=servletConfig;
    }


    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        String name=config.getInitParameter("name");
        System.out.println(name);
        if ("许嵩".equals(name)) {
            System.out.println("是许嵩");
        }
        else{
            System.out.println("蜀云泉最帅");
        }

        //获取所有的参数的名称和值
        Enumeration<String> en=config.getInitParameterNames();
        while (en.hasMoreElements()) {
            String paramName=en.nextElement();
            System.out.println(paramName + "," + config.getInitParameter(paramName));
        }

    }

    public ServletConfig getServletConfig() {
        return null;
    }


    public String getServletInfo() {
        return null;
    }

    public void destroy() {

    }
}

 

HttpServletRequest接口常用的方法

 

我的类是这样的

package main.com.vae.day1;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;

public class HttpServletRequestDemo extends HttpServlet {

    @Override
    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getMethod());    //返回请求的方式:如Get/Post
        System.out.println(req.getRequestURI());//返回类型String,返回请求中的资源名字部分:如/req
        System.out.println(req.getRequestURL());//返回类型StringBuffer,返回请求浏览器地址栏中所有的信息
        System.out.println(req.getContextPath());//返回当前项目的上下文路径
        System.out.println(req.getRemoteAddr()); //返回请求客户机的IP地址
        String userAgent = req.getHeader("User-Agent");  //返回指定名称的请求头的值
        System.out.println(userAgent.contains("MSIE"));
        System.out.println(userAgent);

        System.out.println(req.getParameter("username"));//返回指定参数名的值
        String [] hobbys = req.getParameterValues("hobby");
        System.out.println(Arrays.toString(hobbys));  //返回指定参数名的多个值
        Enumeration<String> names=req.getParameterNames(); //返回所有参数名的Enumeration对象
        while (names.hasMoreElements()) {
            System.out.println("--->" + names.nextElement());
        }

        Map<String,String[]> paramMap=req.getParameterMap();//返回所有参数名的Map对象
        System.out.println(paramMap);

    }



}

浏览器这样输入

http://localhost:8080/req?username=vae&hobby=java&hobby=girl&age=23

结果

HttpServletResponse接口常用的方法

 

package main.com.vae.response;

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.io.PrintWriter;

@WebServlet("/resp")
public class HttpServletResponseDemo extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置输出数据的MIME类型为html的,目的是输出的要以网页的格式展示
        //resp.setContentType("text/html");
        //设置编码格式为中文
        //resp.setCharacterEncoding("UTF-8");

        //上面的两行是必须写的,但是可以精简成一行,如下
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out=resp.getWriter();
        //在浏览器中输出一些内容
        out.println("Vae");
        out.println("许嵩");
        out.println("蜀云泉");

    }
}

 

 

servlet第一个页面,注册页面

 

在webapp下面新建一个HTML文件,叫register.html,代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h3>注册页面</h3>
    <form action="/regi" method="post">
        账号:<input type="text" name="userName" value="默认值" required><br/>   <!--required是Html5的新特性,在以前必填字段我们需要通过js来判断,现在html5实现!-->
        密码:<input type="password" name="passWord"><br/>
        性别:<input type="radio" name="sex" value="boy" checked="checked"/><input type="radio" name="sex" value="girl"/><input type="radio" name="sex" value="none"/>保密<br/>
        爱好:
        <input type="checkbox" name="hobby" value="Vae" checked="checked">许嵩
        <input type="checkbox" name="hobby" value="JJ" checked="checked">林俊杰
        <input type="checkbox" name="hobby" value="shuyunquan">蜀云泉<br/>

        城市:
        <select name="city"  size="1">  <!--size是一次显示几个,option加value就是值是什么,不加默认写的深圳-->
            <option value="sz">深圳</option>
            <option value="bj">北京</option>
            <option value="hn">河南</option>
        </select><br/><br/>

        自我介绍:
        <textarea name="intro" rows="5" cols="30"></textarea>  <!--这里textarea不能换行,必须写两个而且在同一行-->
        <br/><br/>

        <input type="submit" value="注册"/>

    </form>


</body>
</html>

 然后我们再新建一个Registerservlet的Servlet,以前我们每个Servlet都要去xml文件里面添加,很麻烦,所以我们这里使用注解。

package main.com.vae.register;

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.Arrays;

@WebServlet("/regi")
public class RegisterServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name=req.getParameter("userName");
        String passWord=req.getParameter("passWord");
        String sex=req.getParameter("sex");
        String city=req.getParameter("city");
        String intro=req.getParameter("intro");
        String[] hobbys=req.getParameterValues("hobby");

        System.out.println(name);
        System.out.println(passWord);
        System.out.println(sex);
        System.out.println(city);
        System.out.println(intro);
        System.out.println(Arrays.toString(hobbys));

    }
}

使用上面的 HttpServletRequest  的方法,我们可以接收到参数信息

 

然后你会发现一个问题,中文乱码了

 

 

 解决中文乱码问题

 乱码的原因,因为Tomcat对get和post的请求,默认的都是采用 ISO-8859-1 的编码格式,而我们的中文是UTF-8的格式,所以编码不一样,肯定会出现乱码。

解决方案如下:

 

 post方式很简单,直接输入req.setCharacterEncoding,设定一下编码格式就完事。如果是get方式,其实没必要,因为表单里面写get方式的话,参数都会在url里面显示的。所以采用get方式的时候一般都是查询,不会有参数的,有参数也是查询的参数,几乎没有中文。如果非要采用get传中文参数,可以修改Tomcat中的server.xml配置文件

 

 

 Servlet的映射细节

  每一个Servlet都可以在web.xml里面配置,这个配置的映射可以有很多可能

 

 

这个是xml文件里面的,注解里面也可以这样写

@WebServlet(value="/resp",
        initParams = {
        @WebInitParam(name="encoding",value = "utf-8"),
                @WebInitParam(name="name",value = "许嵩")
        }
)

 

Servlet的配置xml和注解使用哪个?

xml

优点:一目了然,结构清晰

缺点:每个Servlet都要配置xml,那100个就要写100次,代码重复,且造成xml文件的臃肿

 

注解

优点:简单,不臃肿

缺点:和Java代码耦合在了一起,高耦合

 

 

Servlet随服务器一起启动

Servlet都是我们访问他们才会出结果。如果你想使得某一个Servlet随着服务器一起启动的话可以这样设置

先看我的Servlet类吧

package main.com.vae.day1;

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


public class MappingServlet extends HttpServlet {

    public MappingServlet() {
        System.out.println("构造器");
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        System.out.println("初始化");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getMethod());
    }
}

 

xml配置方法:

加一个load-on-startup就可以了,完美

    
    <servlet>
        <servlet-name>MappingServlet</servlet-name>
        <servlet-class>main.com.vae.day1.MappingServlet</servlet-class>
        <!--load-on-startup就是设置为启动服务器的时候启动这个Servlet,里面的数字越小,优先级越高-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--向外暴露该Servlet类的一个资源名称,供外键直接访问,资源名称必须以 / 打头-->
    <servlet-mapping>
        <servlet-name>MappingServlet</servlet-name>
        <url-pattern>/map</url-pattern>
    </servlet-mapping>
    

注解的配置方法:

先把我们上面的xml配置注释掉,看看注解的方式

@WebServlet(value = "/map",loadOnStartup = 1)

注解真的是好简单啊。。。

 

 

Servlet的线程不安全问题

在service方法里面这样写

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out=resp.getWriter();
        String name=req.getParameter("name");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        out.println("你输入的名字为:"+name);

    }

然后你打开浏览器输入一个名字

localhost/map?name=许嵩

让别人也输入一个名字,或者你在3秒之内改一个名字,你发现,获取的不是许嵩了,这就是Servlet的线程不安全问题

 

 

 Servlet的缺点

 

 

合并Servlet

比如说我想写一个用户类的增删改查,难道我要写4个Servlet吗?那肯定是不行的,所以有了Servlet的合并,这样

 

 

 

Servlet的上下文路径

比如,我想访问某个Servlet,我要写    路径名称/Servlet名称  因为我们的path经常为空不写,所以在访问Servlet的时候也不写,万一我写path的名称了呢?我写一个aaa,那你代码里面访问Servlet必须加上aaa,我又突然修改了配置文件里面的path为bbb,难道你还要去改代码?所以我们使用上下文路径,就是上图,自动的去获取path的值。

 

以上是关于Java Web之Servlet的主要内容,如果未能解决你的问题,请参考以下文章

Java Web之Servlet技术

servlet和filter的区别

Java Web之Servlet

Java面试之Java Web

Java面试之Java Web

java之servlet学习基础