Servlet入门
4.1. Servlet概述
1、 Servlet
Servlet是sun公司提供的用于开发动态web资源的技术。
2、 servlet生命周期
n 默认情况下,servlet会在第一次被访问的时候被Tomcat实例化,并且驻留内存,然后调用init()方法进行初始化操作,然后调用service方法(“为您服务”),当应用被卸载或者tomcat停掉的时候,释放servlet对象占用的资源(destroy)
范例:运行Servlet,查看Servlet的生命周期
//servlet的生命周期 public class ServletDemo01 extends HttpServlet { //初始化 public void init() throws ServletException { System.out.println("init"); } //sevice(为客户端的“每次”请求进行服务) public void service(ServletRequest request,ServletResponse response){ System.out.println("service"); } //销毁(释放资源) public void destroy() { System.out.println("destory"); } } |
n 如果想要一个Servlet随着容器的启动而实例化和初始化,那么需要在web.xml中进行配置,如下:
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>com.itheima.ServletDemo1</servlet-class> <load-on-startup>1</load-on-startup><!-- 为一个正整数,表明它的启动 顺序 --> </servlet> |
3、 线程安全
n 针对servlet中可能出现的线程安全问题,尽量将变量声明为局部变量。
4、 ServletConfig
n 作用:获取针对某个Servlet的配置信息
通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
范例:
Web.xml中的初始化参数信息:
<servlet> <servlet-name>ServletDemo3</servlet-name> <servlet-class>com.itheima.ServletDemo3</servlet-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>username</param-name> <param-value>admin</param-value> </init-param> </servlet> |
编程得到参数化信息:
public class ServletDemo3 extends HttpServlet { private String defaultCoding = "UTF-8"; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test2(); } //获取所有的参数 private void test2() { Enumeration enumers = getServletConfig().getInitParameterNames(); while (enumers.hasMoreElements()) { String paramName = (String) enumers.nextElement(); System.out.println(paramName+"="+getServletConfig().getInitParameter(paramName)); } } //获取指定参数 private void test1() { String encoding = getServletConfig().getInitParameter("encoding"); if(encoding==null) encoding = defaultCoding; System.out.println(encoding); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
5、ServletContext
可以把它看做一个代表,代表当前的整个JavaWeb应用。(某个Web应用的总管家)
Tomcat(WEB容器)在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
作用:
1、多个Servlet之间进行数据共享。整个Web应用数据共享。
2、获取web应用的全局参数
全局参数配置在web.xml的根元素下<context-param>
得到代表整个web应用的总管家:
public class ServletDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext();//得到代表整个web应用的总管家 } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
**ServletContext中有一个Map属性
重要:
Object getAttribute(String name):name相当于域Map的key,返回的是value
void setAttribute(String name,Object obj):
void remove(String name):
Enumeration getAttributeNames():获取Map域中的所有的key。
ServletContext的应用:
案例1:多个Servlet通过ServletContext对象实现数据共享。
即证明ServletDemo4和ServletDemo5共享数据:(Demo4里面设置数据Demo5里面可 以拿到数据)
在ServletDemo4里面设置数据:
public class ServletDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext();//得到代表整个web应用的总管家 sc.setAttribute("p", "pp"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
在ServletDemo5里面拿到数据:
public class ServletDemo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); String value = (String)sc.getAttribute("p"); System.out.println(value); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
案例2:获取WEB应用的全局参数(全局参数配置在web.xml的根元素下<context-param>)
//获取全局参数 public class ServletDemo6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); String value = sc.getInitParameter("encoding"); System.out.println(value); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } |
案例3:读取各种资源文件的三种方式:
1. ServletContext方式读取配置文件,此方法可以读取web环境中所有的文件
ServletContext context = getServletContext(); String path = context.getRealPath("/cfg.properties"); //得到路径 InputStream in = new FileInputStream(path); //通过路径读取文件 Properties p = new Properties(); P.load(in); p.getProperty("name"); |
2.类加载器方法读取配置文件,此方法可以使用在web环境下,也可以使用在非web环境下,但是只能读取加载类下的所有文件
ClassLoad load = Demo1.class.getClassLoad(); URL url = load.getResource("cfg.properties"); //得到URL InputStream in = new FileInputStream(url); Properties p = new Properties(); P.load(in); p.getProperty("name"); |
3.ResourceBundle方法读取配置文件,此方法读取配置文件非常简单,但是只能读取加载类下的.properties文件
ResourceBundle rb = ResourceBundle. getBundle("cfg3"); //基名,就是去掉扩展名的 String value = rb.getString(); System.out.print(value); |
4.下载文件
String path=getServletContext().getRealPath("/image/科比.jpg"); resp.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(path.substring(path.lastIndexOf("//")+1), "UTF-8")); //设置响应头 InputStream in = new FileInputStream(path);//读取数据 OutputStream out=resp.getOutputStream(); int len=0; byte [] b=new byte[1024]; while((len= in.read(b))!=-1){ out.write(b, 0, len); } in.close(); out.close(); |
请求重定向
特点:
1.浏览器会发送两次请求
2.浏览器地址会发生改变
应用场景:
1.网上购物,使用请求重定向,用户刷新的就只是购物车界面,如果使用转发,那么每次用户刷新,就会添加一次购买
2.用户登录
//设置重定向方法一: resp.setStatus(302); //设置响应码 resp.setHander("location","/day05.a.html"); //设置重定向 //设置重定向方法二: resp.sendRedirect("/day05/a.html"); |
注意:
在servlet中,不能同时调用getOutputStream()和getWriter()方法,如果同时调用,将会报出getOutputStream() has already been called for this response的错误
Request:
得到客户端向服务端发送的信息
getRequestURL方法返回客户端发出请求时的完整URL。 getRequestURI方法返回请求行中的资源名部分。 getQueryString 方法返回请求行中的参数部分。 getRemoteAddr方法返回发出请求的客户机的IP地址 getRemoteHost方法返回发出请求的客户机的完整主机名 getRemotePort方法返回客户机所使用的网络端口号 getLocalAddr方法返回WEB服务器的IP地址。 getLocalName方法返回WEB服务器的主机名 getMethod得到客户机请求方式 |
获取请求头
getHander(); //获取单一的请求头 getHanderNames(); //获取所有的请求头名称 |
获取请求参数(客户端提交的请求数据).
用户提交的请求数据,常用的就是GET方式和POST方式,其中
GET方式获取到的就是 "localhost:8080/index?name=admin&password=123 ",中的name和password.
POST方式获取到的是正文部分.
特别注意:用户所有输入的数据都是String类型
getParameter(name); //得到单一参数的值,相当于getParameterValues的一个特例,如果没有这个name,就返回null,如果用户没有输入,就返回空字符串,如果出现的同名的参数,那么这个方法只能获取第一个. //得到单一的参数 private void test1(HttpServletRequest req,HttpServletResponse resp) throws Exception { String value=req.getParameter("username"); //由参数名得到参数值 resp.getOutputStream().write(value.getBytes()); } |
getParameterValues(name); //得到同名所有同名参数的值 String[] values=req.getParameterValues("username");//获取所有参数名问username的值 if(values!=null&&values.length>0){//健壮性判断,html中有这个参数,并且提交的值不为空 for (String value:values) { resp.getOutputStream().write(value.getBytes()); } } |
getParameterNames(); //获取所有的请求参数名 //得到所有的参数 private void test2(HttpServletRequest req,HttpServletResponse resp) throws Exception { // TODO Auto-generated method stub Enumeration es=req.getParameterNames(); //得到所有参数的名称 while(es.hasMoreElements()){ //迭代所有参数名称 String name=(String)es.nextElement(); //通过参数名称得到参数的值 resp.getOutputStream().write(req.getParameter(name).getBytes()); } } //getParameterNames()封装数据到对象中 Student stu = new Student(); System.out.println("封装前: "+stu); Enumeration en=req.getParameterNames(); while(en.hasMoreElements()){ String name=(String)en.nextElement();//得到参数名 try { PropertyDescriptor pd=new PropertyDescriptor(name, stu.getClass());//操作bean Method method=pd.getWriteMethod();//通过反射得到set方法 method.invoke(stu, req.getParameter(name)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { resp.getOutputStream().write(("封装后 :"+stu).getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } |
getInputStream(); 以流的方式获取正文信息 |
getParameterMap(); //做框架非常又有,搭配beanUtils Student stu =new Student(); System.out.println("封装前: "+stu); Map<String,String[]> map=req.getParameterMap(); BeanUtils bu=new BeanUtils(); try { bu.populate(stu, map); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } |
各种表单输入域:
请求参数中的中文乱码:
Request的请求转发和重定向:
请求转发: 请求地址不会变,浏览器发出了一次请求:两个处理Servlet共享同一个request和response.
转发: 发送端: RequestDispatcher rd=req.getRequestDispatcher("ResquestTest2");//设置转发地址 rd.forward(req, resp);//转发 接收端: String value=(String)req.getAttribute(name); |
转发和包含:
转发:源组件所有的正文都无效.转发前会清空response对象的缓存,但是不要再转发前刷新缓存.
包含: 目标组件的所有响应头和响应码都无效,包含前会清空response中的响应头和响应码
javaWeb 中各种路径的写法:
绝对路径: 如果路径给库护短用,需要加项目名称 /day6 ; 如果是给服务器的路径,就不要骄傲项目名,"/"代表项目名称