Servlet(Server Applet) 详解

欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot

Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。

Servlet的工作模式

  1. 客户端发送请求至服务器
  2. 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器
  3. 服务器将响应返回客户端

Servlet 的工作原理

 Servlet接口定义了Servlet与servlet容器之间的契约:
    Servlet容器将Servlet类载入内存,并产生Servlet实例和调用它具体的方法。
    在一个应用程序中,每种Servlet类型只能有一个实例。

ServletRequest对象和ServletResponse对象:
    ServletRequest对象和ServletResponse对象都是由Servlet容器(例如TomCat)封装好的,
    并不需要程序员去实现,程序员可以直接使用这两个对象。

ServletContext对象:
    这个对象中封装了上下文(应用程序)的环境详情,可以共享应用程序的信息。。
    每个应用程序只有一个ServletContext。

ServletConfig对象:
    配置信息


web.xml的配置文件:

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.LoginServlet</servlet-class>
    <!-- 初始参数: 这些参数会在加载web应用的时候,封装到ServletConfig对象中 -->
    <init-param>
    	<param-name>location</param-name>
    	<param-value>aaa</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>


转发:request.getRequestDispatcher("/welcome.jsp").forward(request,response);

重定向:response.sendRedirect("/welcome.jsp");

二者区别:
    转发不会改变地址栏中的URL,而重定向则会改变
    转发只能访问到当前web应用中的内容,而重定向则可以访问到任意web应用中的内容
    转发后,在转发后的页面中仍然可以使用原来的request对象,而重定向,原来的request对象则失去作用

Servlet接口

package javax.servlet;

public interface Servlet {

    /**
     * 当Servlet第一次被请求时,Servlet容器就会调用这个方法(传入ServletConfig对象),
     * 从而对Servlet对象进行初始化。但是这个方法在后续请求中不会在被Servlet容器调用
     */
    void init(ServletConfig var1) throws ServletException;

    //返回由Servlet容器传给init()方法的ServletConfig对象
    ServletConfig getServletConfig();

    /**
     * 每当请求Servlet时,Servlet容器就会调用这个方法。
     */
    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    /**
     * 当要销毁Servlet时,Servlet容器就会调用这个方法。
     */
    void destroy();
}


ServletConfig接口:

    public interface ServletConfig {
        String getServletName();

        ServletContext getServletContext();

        String getInitParameter(String var1);

        Enumeration getInitParameterNames();
    }


GenericServlet抽象类:
    GenericServlet实现了Servlet和ServletConfig接口,为Servlet接口中的所有方法提供了默认的实现

HttpServlet抽象类

HttpServlet在实现Servlet接口时,覆写了service方法:
    该方法体内的代码会自动判断用户的请求方式:
        如为GET请求,则调用doGet方法。
        如为Post请求,则调用doPost方法。
    因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。

package javax.servlet.http;

public abstract class HttpServlet extends GenericServlet implements Serializable {

    public HttpServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_put_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_delete_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String CRLF = "\r\n";
        String responseString = "TRACE " + req.getRequestURI() + " " + req.getProtocol();

        String headerName;
        for(Enumeration reqHeaderEnum = req.getHeaderNames();
                reqHeaderEnum.hasMoreElements();
                responseString = responseString + CRLF + headerName + ": " + req.getHeader(headerName)) {
            headerName = (String)reqHeaderEnum.nextElement();
        }

        responseString = responseString + CRLF;
        int responseLength = responseString.length();
        resp.setContentType("message/http");
        resp.setContentLength(responseLength);
        ServletOutputStream out = resp.getOutputStream();
        out.print(responseString);
        out.close();
    }

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }

        this.service(request, response);
    }
}

HttpServletRequest接口

HttpServletRequest表示Http环境中的Servlet请求:

    String getContextPath();    //项目(应用)名(当前应用的根目录)

    Cookie[] getCookies();    //返回一个cookie对象数组

    String getHeader(String var1);    //返回指定HTTP请求头的值

    String getMethod();    //返回客户端的请求方式

    String getQueryString();    //Get请求提交url地址后的参数字符串

    HttpSession getSession();    //返回与这个请求相关的会话对象

    String getRequestURI()    // app/login.jsp

    StringBuffer getRequestURL()    // http://localhost:8080/app/login.jsp

    String getParameter(String name)

    String[] getParameterValues(String name)

    Enumeration getParameterNames()

    Map<String,String[]> getParameterMap()


乱码解决:
    Get:
            String name = request.getParameter("name");    //接收数据
            name =new String(name.getBytes("ISO8859-1"), "UTF-8")
    Post:
            request.setCharacterEncoding("UTF-8");

HttpServletResponse接口

void addCookie(Cookie var1);    //给这个响应添加一个cookie

void addHeader(String var1, String var2);    //给这个请求添加一个响应头

setHeader(String name, String value)

void sendRedirect(String var1) throws IOException;    //重定向

void setStatus(int var1);    //设置响应行的状态码


PrintWriter getWriter():
    获得字符流,通过字符流的write(String s)方法可以将字符串设置到response缓冲区中,
    随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。

ServletOutputStream getOutputStream():
    获得字节流,通过该字节流的write(byte[] bytes)可以向response缓冲区中写入字节,再由Tomcat服务器将字节内容组成Http响应返回给浏览器。


乱码解决:
    response.setContentType("text/html;charset=UTF-8");

示例

@WebServlet("/addServlet")    //该注解等价于在web.xml中配置的该servlet的<servlet-mapping>元素中的<url-pattern>
public class AddServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");    //处理乱码
        Map<String, String[]> parameterMap = request.getParameterMap();    //获取参数
        User user = new User();
        try {
            BeanUtils.populate(user, parameterMap);    //封装参数
        } catch (Exception e) {
            e.printStackTrace();
        }
        ServiceImpl service = new ServiceImpl();    //转发到service处理
        service.addUser(user);
        //response.setContentType("application/json;charset=utf-8");
        //response.getWriter().write("添加成功!");
        response.sendRedirect(request.getContextPath() + "/findUserServletByPage");    //重定向
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}


@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
    private List<String> words = new ArrayList<>();

    public void init(FilterConfig config) {
        String realPath = config.getServletContext().getRealPath("/WEB-INF/classes/敏感词汇.txt");
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(realPath), Charset.forName("utf-8")));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                words.add(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //创建代理对象
        ServletRequest getParameter = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), 
                                        req.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("getParameterMap")) {
                    //增强该方法
                    Map<String, String[]> map = (Map<String, String[]>) method.invoke(req, args);
                    //处理参数列表中的敏感词汇
                    . . .
                    return map;
                }
                return method.invoke(req, args);
            }
        });
        chain.doFilter(getParameter, resp);
    }

    public void destroy() {
    }
}
posted @ 2019-09-19 19:42  LittleDonkey  阅读(477)  评论(0编辑  收藏  举报