Servlet学习

知识点:
△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类的成员变量,而应该声明成局部变量
//当然,如果我们数据正好想让它共用,那么就声明成类的成员变量

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值