package com.mystudy.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.Request; public class helloServlet extends HttpServlet { //http请求方法不只是post和get,还有options用于返回服务器支持的方法,put方法用于上传指定的资源, //delete方法用于删除指定的资源,head和get相同只是返回http的报头,一般用到的只有post和get @Override public void init() throws ServletException { System.out.println("========servlet init without param============"); super.init();//无参数的时候可以不调用super } @Override public void init(ServletConfig config) throws ServletException { System.out.println("========servlet init with param============"); //有参数时需要手动调用super方法,init方法并不一定要重写,在需要servlet初始化的时候做一些操作,则重写,其他时候也不需要重写 //有参数的init方法在父类中会显示的调用无参的init方法。 super.init(config); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("========servlet service============"); PrintWriter p=resp.getWriter(); p.print("hello world"); p.close(); } @Override public void destroy() { //当servlet容器销毁servlet的时候才会调用destroy方法 System.out.println("========servlet destroy============"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub super.doPost(req, resp); PrintWriter p=resp.getWriter(); p.print("hello world"); p.close(); String userNameString=req.getParameter("uname"); String passwordString=req.getParameter("upwd"); System.out.println("用户名: "+userNameString); System.out.println("密码: "+passwordString); //请求重定向,直接返回这个url,浏览器会重新访问返回 的url,因此这个url可以是当前应用的也可以是其他应用的地址, //那么浏览器的请求实际上完成的是两次,第一次访问目标地址,第二次访问重定向地址 resp.sendRedirect(req.getContextPath()+"/04/success.jsp"); //请求转发 和请求重定向不一样的是,请求转发只有一个http请求,不会产生第二次, //并且转发的地址必须是同一个应用中的地址,各个组件公用一个req请求和resp返回对象 String forwordString="/04/error.jsp"; RequestDispatcher rDispatcher=req.getRequestDispatcher(forwordString); rDispatcher.forward(req, resp); } } 还需要在web.xml中配置servlet <servlet> <servlet-name>helloServlet</servlet-name> <servlet-class>com.mystudy.servlet.helloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
通过HttpServlet类中的service方法可以看到,他的功能是根据请求的方法,自动的映射到不同的请求处理方法中,如果请求是get,那么请求交给doget(),如果是post交给dopost()。那么默认的service方法相当于一个请求转发的功能,因此如果我们自己重写servce方法, 父类HttpServlet中的service方法就会失效
所以收到的任何请求都会由我们自己覆写的service方法来处理
如果我们的servlet中只有service方法, 是没有问题的
但值得注意的是,一定要在执行完自己代码后调用父类service方法, super.service;
否自你的doGet和doPost是不会被执行的
servlet的过滤器 filter
Filter,过滤器,顾名思义,即是对数据等的过滤,预处理过程。为什么要引入过滤器呢?在平常访问网站的时候,有时候发一些敏感的信息,发出后显示时 就会将敏感信息用*等字符替代,这就是用过滤器对信息进行了处理。这只是一个简单的例子,当然,过滤器那么强大,它的功能也不可能局限于此,它不仅能预处 理数据,只要是发送过来的请求它都是可以预处理的,同时,它还可以对服务器返回的响应进行预处理,这样,大大减轻了服务器的压力。例如,实现URL级别的 权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能
过滤作用,对从客户端向服务器端发送的请求进行过滤,也可以对服务器端返回的响应进行处理。它使用户可以改变一个request和修改一个 response.。Filter 不是一个servlet,它不能产生一个response,但是它能够在一个request到达servlet之前预处理request,也可以在 response离开servlet时处理response。换句话说,filter其实是客户端与servlet中间的一个传递者,并且它可以对要传递 的东西进行修改。
如何实现拦截
- 当客户端发生请求后,在HttpServletRequest 到达Servlet 之前,过滤器拦截客户的HttpServletRequest 。
- 根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
- 在过滤器中调用doFilter方法,对请求放行。请求到达Servlet后,对请求进行处理并产生HttpServletResponse发送给客户端。
- 在HttpServletResponse 到达客户端之前,过滤器拦截HttpServletResponse 。
- 根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。
- 最后,HttpServletResponse到达客户端。
package com.mystudy.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; public class FilterOne implements Filter { /** * Default constructor. */ public FilterOne() { // filter的构造函数 System.out.println("========filter one construct==========="); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // filter 的初始化,可以获取在注册时候的参数 System.out.println("========filter one init==========="); // System.out.println("param= "+fConfig.getInitParameter("encoding")); } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 过滤器的具体实现,在请求进入对应的servlet之前输出一句话,在退出servlet之后输出一句话。 System.out.println("========filter one dofilter start==========="); chain.doFilter(request, response); System.out.println("========filter one dofilter end==========="); } /** * @see Filter#destroy() */ public void destroy() { // 过滤器销毁的时候执行 System.out.println("========filter one destroy==========="); } } 在web.xml中进行注册,和servlet一样。 <filter> <filter-name>FilterOne </filter-name> <filter-class>com.mystudy.filter.FilterOne </filter-class> <init-param>//指定参数 <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>FilterOne </filter-name> <url-pattern>/*</url-pattern>//对于所有该应用的请求都做拦截 </filter-mapping>
对于一个应用可以有多个过滤器,那么过滤器按照其配置的顺序进行调用。在dofilter()方法中的Filterchain对象就是放行到下一层过滤器的作用,可以通过
chain.doFilter(request, response);
实现。
如果没有filter了,那么直接放行到servlet,具体如上图那样。
//一个简单的字符编码过滤器,在注册该过滤器的时候指定一个参数encoding,值为UTF-8 //每次请求来的时候截获检查是不是指定的编码方式,不是就需要进行修改 public void init(FilterConfig fConfig) throws ServletException { charEncodingString=fConfig.getInitParameter("encoding"); if (charEncodingString==null) { throw new ServletException("encoding can't null"); } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (!charEncodingString.equals(request.getCharacterEncoding())) { request.setCharacterEncoding("UTF-8"); } response.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); }
servlet本质是什么?
servlet接口定义的是一套处理网络请求的规范,所有实现servlet的类,都需要实现它那五个方法,其中最主要的是两个生命周期方法 init()和destroy(),还有一个处理请求的service(),也就是说,所有实现servlet接口的类,或者说,所有想要处理网络请求的类,都需要回答这三个问题:
- 你初始化时要做什么
- 你销毁时要做什么
- 你接受到请求时要做什么
这是Java给的一种规范!servlet是一个规范,那实现了servlet的类,就能处理请求了吗?不是
我们不会在servlet中写什么监听8080端口的代码,servlet不会直接和客户端打交道!
那请求怎么来到servlet呢?答案是servlet容器,比如我们最常用的tomcat,,我们需要把servlet部署到一个容器中,不然你的servlet压根不会起作用。
tomcat才是与客户端直接打交道的家伙,他监听了端口,请求过来后,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,tomcat再把这个response返回给客户端。
jsp和servlet的区别是什么?
jsp的本质就是servlet,jsp经过编译之后就成了servlet。
- Servlet在Java代码中通过HttpServletResponse对象动态输出HTML内容
- JSP在静态HTML内容中嵌入Java代码,Java代码被动态执行后生成HTML内容
- Servlet能够很好地组织业务逻辑代码,但是在Java源文件中通过字符串拼接的方式生成动态HTML内容会导致代码维护困难、可读性差。servlet更擅长逻辑控制
- JSP虽然规避了Servlet在生成HTML内容方面的劣势,但是在HTML中混入大量、复杂的业务逻辑同样也是不可取的。jsp更擅长页面显示
Servlet中没有内置对象,所需要必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到.
servlet的构造函数和init方法????
首先,构造函数是有的,虽然我们通常不写servlet的构造函数,但是就像任何一个普通的java类一样,编译器会自动给你生成一个默认构造函数;
其次,构造函数和init方法都会被web容器调用,而且是先调用构造函数,然后调用init方法;
最后,貌似容器只会调用默认构造函数,所以如果你自己写了带参数的构造函数(系统就不会自动生成默认构造函数),容器初始化servlet就会出错……P.S.:任何时候都不推荐自己写构造函数来初始化servlet类,哪怕你自己提供不带参数的构造函数……