Servlet学习

来源:互联网 发布:mysql join 默认值 编辑:程序博客网 时间:2024/06/05 16:05

知识点:
△Tomcat在启动时会读取一系列的配置文件和jar文件,顺序如下:
i. Tomcat自己的conf/server.xml
ii. Tomcat自己的conf/web.xml
iii. Tomcat自己的tomcat-users.xml
iv. D:\apache-tomcat-7.0.30\conf\Catalina\localhost目录下的 *.xml
v. 加载webapps目录下的所有项目中的web.xml

△WEB-INF目录为安全目录,里面的所有资源必须在web.xml中进行配置,否则外面无法访问。

△有关路径中起始“/”的含义:
1)如果在前端页面(JSP页面)中,是代表Tomcat的根目录
2)如果在web.xml或servlet中,是代表项目根目录
3)项目根目录 = Tomcat根目录 + 项目名
4)无论是前面页面还是web.xml,servlet中,如果路径以“/”开始是绝对路径,否则是相对路径

△在JavaEE领域,sun公司只做接口或抽象类(标准),由各服务器产商(如Tomcat)来做实现。
我们做项目如写servlet,我们实现sun公司的接口或抽象类,则所有服务器都能兼容。

△我们项目中所用到的类有以下3个地方可以放(加载)
1) 加载:Tomcat根目录/项目名/WEB-INF/classes目录下 —-放:项目中的src目录
2) 加载:Tomcat根目录/项目名/WEB-INF/lib目录下 —-放:项目中的WebRoot/WEB-INF/lib目录
3) 加载(放):Tomcat根目录/lib <—所有项目共用的(Tomcat的运行环境)
※1※注意,法1中以.class(.java)的形式存在。法2和法3是以.jar的形式存在
※2※如果以上几个地方存在相同的类,则优先级是: classes > 项目下/WEB-INF/lib > Tomcat/lib

△我们开发servlet一般有3种方法
1)实现Servlet接口—最底层的

2)继承GenericServlet
GenericServlet类中有一个空参init()方法,其实是适配器模式中的一个技术细节:在带参init方法中帮我们把config赋好值,然后调用空参且空实现init()方法–该方法是专门给子类覆盖的。—在适配器中帮我们做一部分事情,然后调用我们的覆盖方法

3)继承HttpServlet—-最常用的方式(而且一般采用向导来开发)
注意,该方式下一定要覆盖对应的请求处理方法(如doGet(req,resp)或doPost(req,resp)等),否则会出现405错误(不支持相应的服务请求)。

△运行环境:
JavaSE中的运行环境通常是MyEclipse中。
JavaEE的运行环境是Tomcat容器。

△JavaEE项目中,资源存放的两个地方通常有两种:
1) src下,访问方式:通过类反射到classpath下去获取
2) WebRoot下,访问方式:String dir = getServletContext().getRealPath(“/imgs”);//参数可目录也可文件名
File file = new File(dir);

项目开发中Servlet的细节和知识点:

△web.xml配置文件
1).为Servlet配置服务提供路径,将项目中的前端请求和后台服务想连接起来。

连接到后台服务类

<servlet>    <servlet-name>ServletContext</servlet-name>    <servlet-class>cn.hncu.servlets.ServletContextDenmo</servlet-class>  </servlet>

连接前端服务请求

<servlet-mapping>    <servlet-name>ServletContext</servlet-name>    <url-pattern>/count</url-pattern>  </servlet-mapping>

1).为Servlet服务提供参数,

 <init-param>        <param-name>Charset</param-name>        <param-value>UTF-8</param-value>    </init-param>

后台设置参数并运用,可以达到修改配置文件到达维护的目的
(该参数是单独为此服务设置,也可以为所有服务设置)

public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        PrintWriter out = response.getWriter();        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");        out.println("<HTML>");        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");        out.println("  <BODY>");        ServletConfig config = this.getServletConfig();        String charset = config.getInitParameter("Charset");        request.setCharacterEncoding(charset);        out.println("charset1"+charset+","+"charset2"+this.getInitParameter("Charset"));        out.println("</br>");        Enumeration<String> it =this.getInitParameterNames();        while(it.hasMoreElements()){            String name = it.nextElement();            String value = config.getInitParameter(name);            out.println(value+"</br>");            System.out.println(value);        }        response.setCharacterEncoding(charset);        out.println("  </BODY>");        out.println("</HTML>");        out.flush();        out.close();    }

配置所有服务均可以调用的参数

<!-- 配置ServletContext作用域的初始化参数,所有servlet共享的 -->  <context-param>    <param-name>charset</param-name>    <param-value>UTF-8</param-value>  </context-param>

获取方法

/用在Web.xml中配置ServletContext作用域的初始化参数,来写成活的        String charset = getServletContext().getInitParameter("charset");        request.setCharacterEncoding(charset);        System.out.println(">>>"+charset);        String str = getInitParameter("charset");//获取的是当前servlet专用的        System.out.println("str:"+str);

△servlet的三种开发方式

第一种:直接通过实现Servlet接口的方式(最底层的开发方式)

@Override    public void init(ServletConfig config) throws ServletException {        System.out.println("1初始化");    }    @Override    public ServletConfig getServletConfig() {        System.out.println("2读取该servlet在web.xml中的配置参数...");        return null;    }    @Override    public void service(ServletRequest req, ServletResponse resp)            throws ServletException, IOException {        System.out.println("3--进行服务响应....");    }    @Override    public String getServletInfo() {        System.out.println("很少用,一般是返回该servlet的信息如作者和版本等");        return null;    }    @Override    public void destroy() {        System.out.println("4--消亡了....");    }

需要重写几中方法:
service是请求一次调用一次。其他的方法是整个服务器启动一次调用一次。包括初始化,消亡等等。

第二种:通过继承GenericServlet类

1.只需要完成实现service方法即可(想对于第一种简单化了)

2.若需要初始化覆盖 init()方法即可。覆盖 init(ServletConfig config),必须要保留 super.init(config);否则会空指针异常。原因简单来说少了一句

this.config = config.  

第三种:通过继承HttpServlet类(主要针对网络的HTTP协议的服务)
格局前端提交方式覆盖父类相应方法
例如常见的dopost doget doput 等等

利用Servlet完成几个功能来,熟悉Servlet的以下几个类

ServletConfig – 代表Servlet的初始化配置参数。
从服务器打开到下次启动前一直是同有个对象
ServletContext – 代表整个Web项目。

留言板功能实现代码

public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        PrintWriter out = response.getWriter();        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");        out.println("<HTML>");        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");        out.println("  <BODY>");        //获取表单提交的留言        //request.setCharacterEncoding("utf-8");//写死的        //用在Web.xml中配置ServletContext作用域的初始化参数,来写成活的        String charset = getServletContext().getInitParameter("charset");        request.setCharacterEncoding(charset);        System.out.println(">>>"+charset);        String str = getInitParameter("charset");//获取的是当前servlet专用的        System.out.println("str:"+str);        String msg = request.getParameter("msg");        //留言板必须获取提交用户的信息(IP,time)----法律意识        String ip = request.getRemoteAddr();        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");        String time = sdf.format( new Date() );        //把当前用户的留言(来自表单)和原来的留言信息合并        if(msg!=null && !msg.trim().equals("") ){//当前用户提交有效留言            //如果要做得好一些,要把msg中非法的字符(如<、'、"、/>等)转换或替换            msg = msg.replaceAll("<", "&lt;");            String msgs = (String) getServletContext().getAttribute("msgs");            if(msgs==null){                msg = time+"&nbsp;&nbsp;"+ip+": " + msg;                getServletContext().setAttribute("msgs", msg);            }else{                msgs = msgs + "<br/>"+ time+"&nbsp;&nbsp;"+ip+": " + msg;                getServletContext().setAttribute("msgs", msgs);            }        }        //输出留言合并后的留言信息        String info = (String) getServletContext().getAttribute("msgs");        String div = "<div style='border:1px solid red;width:600px;" +                "height:400px;overflow:auto;'>"+info+"</div>";        if(info!=null){            out.println(div);        }        out.println("<hr/>");//分隔线        //输出留言表单        String form = "<form action='chat'method='post'>"                + "留言:<input type='text' name='msg'/>"                + "<input type='submit' value='发送'/>" + "</form>";        out.println(form);        out.println("  </BODY>");        out.println("</HTML>");        out.flush();        out.close();    }

网站点击量统计:主要是因为ServletContext是同一个,服务器不关每次请求都是同一个。

public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        PrintWriter out = response.getWriter();        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");        out.println("<HTML>");        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");        out.println("  <BODY>");        ServletContext ctx = getServletContext();        Integer count = (Integer) ctx.getAttribute("count");        if(count==null){            count=1;        }else{            count++;        }        getServletContext().setAttribute("count", count);        out.println("点击量:"+count);        out.println("  </BODY>");        out.println("</HTML>");        out.flush();        out.close();    }

设置一个默认见面: XML配置访问路径为 “/” 当在网站内前端发来请求服务不是XML已经配置好的服务时,就会通过“/” 映射到改服务

public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        PrintWriter out = response.getWriter();        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");        out.println("<HTML>");        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");        out.println("  <BODY>");        out.println("<font size=30 color=red>杯具了,您找的页面不存在!</font>");        out.println("  </BODY>");        out.println("</HTML>");        out.flush();        out.close();    }

从服务器下载文件: 要设置响应头,告诉浏览器是下载。同时要不下载的文件对拷过来传给前端。

public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        //基本套路:从服务器本地硬盘地址中把文件读取出来,发送到前端(通过response)        //为便于大家掌握文件下载技术的核心思想,只考虑文件名是死的情况(其实可以从前端提交的参数中读取)        //※设置响应头,告诉浏览器用它的默认下载程序来接收后台发送的数据(有的浏览器是弹出下载窗口,也有的浏览器是启动迅雷)        response.setContentType("application/force-download");        //如果不设置上面一句响应头,则浏览器是自己直接打开即浏览        //String fn="b.jpg";        String fn="过一会儿下课.jpg";        fn=URLEncoder.encode(fn,"UTF-8");//如果进行编码,则可以兼容中英文(其实英文可以不用编码,但编码对它没影响)        //※设置响应头,告诉浏览器这个下载的文件名是什么        response.setHeader("Content-Disposition", "attachment;filename=\""+fn+"\"");        //真正的文件数据发送在下面一段        String filename="/imgs/3.jpg";        String path = getServletContext().getRealPath(filename);        System.out.println(path);        //流拷贝        InputStream in = new FileInputStream(new File(path) );        OutputStream out = response.getOutputStream();        byte buf[] = new byte[512];        int len=0;        while((len=in.read(buf))!=-1){            out.write(buf, 0, len);        }        in.close();        out.close();    }

获取参数的几种方法

//读取servlet中的初始化参数        //////////////法1//////////////////        ServletConfig config = getServletConfig();        String charset = config.getInitParameter("charset");        String age = config.getInitParameter("age");        out.println("法1,charset:" + charset+" ,age:"+age);        out.println("<br/>");        //////////////法2//////////////////        String charset2 = this.getInitParameter("charset");        String age2 = this.getInitParameter("age");        out.println("法2,charset:" + charset2+" ,age:"+age2);        out.println("<br/>");        /////////////法3:写活的---遍历参数名和值////////////////        out.println("-------法3-------<br/>");        Enumeration<String> en = this.getInitParameterNames();        while(en.hasMoreElements()){            String name = en.nextElement();            String value = getInitParameter(name);            out.println(name+","+value+"<br/>");        }

读取服务器中某个项目中的全部文件:这儿以图片为例

public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        PrintWriter out = response.getWriter();        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");        out.println("<HTML>");        out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");        out.println("  <BODY>");        /*过渡版,写死的        for(int i=1;i<10;i++){            String img = "<img width='200px' height='200px' src='imgs/"+i+".jpg'/><br/>";            out.println(img);        }        */        //写活的,到本地服务器的图片目录中把所有图片名遍历出来,然后拼接成<img>标记输出        /*         File dir = new File("."); //这个目录是:Tomcat/bin        String names[] = dir.list();        for(String name:names){            System.out.println(name);        }        */        //※※一个技术: 如果访问WebRoot下的资源文件        /*知识点讲解        ServletContext ctx = getServletContext();        String path1 = ctx.getContextPath(); //项目名---通过代码自动获取---活的        System.out.println("path1:"+path1); //   "/servletDemo3"        String path2 = ctx.getRealPath("/imgs"); //服务器磁盘的绝对路径(带盘符),,File只能用这种        System.out.println("path2:"+path2); // D:\apache-tomcat-7.0.30\webapps\servletDemo3\imgs        */        String path = getServletContext().getRealPath("/imgs");//获取项目WebRoot下的“imgs”文件夹的绝对路径--带盘符        File dir = new File(path);        String filenames[] = dir.list();        for(String filename: filenames){            String img = "<img width='200px' height='200px' src='imgs/"+filename+"'/>";            out.println(img);        }        out.println("  </BODY>");        out.println("</HTML>");        out.flush();        out.close();    }

线程安全:

//因为servlet是单例,所有浏览器(多用户,多线程)是共享这一个servlet的,也共享这个对象中的所有成员变量
//上面是通俗但不严谨的说法。严格来讲是多个请求(request)共享这个单例servlet。
private String name;

//由本例出现的多请求串数据(this.name)得出,如果我们以后不希望多个请求出现串数据的情况,不能把数据声明成servle类的成员变量,而应该声明成局部变量//当然,如果我们数据正好想让它共用,那么就声明成类的成员变量

服务器上帝资源文件明和路径尽量避免使用中文名,因为请求资源时会对路径名字进行编码。会导致错误

原创粉丝点击