• Java Web之Servlet


      什么是Servlet?

      Servlet有什么用?

      Idea写一个Servlet程序

    一、新建一个类

    我新建了一个HelloServlet类,要继承一个servlet接口 javax.servlet.Servlet,但是你是打不出来的,原因是没有包,看第二步导入包

    然后就可以继承接口方法了,在service方法里面写一个输出语句吧

    package main.com.vae.servletDemo;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import java.io.IOException;
    
    public class HelloServlet implements javax.servlet.Servlet{
        public void init(ServletConfig servletConfig) throws ServletException {
    
        }
    
        public ServletConfig getServletConfig() {
            return null;
        }
    
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("许嵩小名许甜甜");
        }
    
        public String getServletInfo() {
            return null;
        }
    
        public void destroy() {
    
        }
    }

    二、导入servlet的jar包

    你的Tomcat的lib文件夹里面有一个servlet的jar包,复制到WEB-INF下的lib文件夹内,如图

    三、修改web.xml

    打开WEB-INF下的web.xml,加上这几个

        <servlet>
            <servlet-name>HelloServlet</servlet-name>
            <servlet-class>main.com.vae.servletDemo.HelloServlet</servlet-class>
        </servlet>
    
        <!--向外暴露该Servlet类的一个资源名称,供外键直接访问,资源名称必须以 / 打头-->
        <servlet-mapping>
            <servlet-name>HelloServlet</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>

    四、你的webapp的路径,在Tomcat里面修改

    如果你不修改Tomcat的server.xml里面的Context标签,那么你的Tomcat打开后出现的是官方的Tomcat猫界面,我们修改了context之后,如下

    五、重启Tomcat

    输入localhost/hello (备注,我的端口号改为80了,你们默认的是8080),查看idea的控制台

     Servlet的生命周期

    Servlet的请求流程

     ServletConfig接口初始化参数

    我写一个类,继承Servlet接口,想在service方法里面写一个判断,判断name是许嵩,就输出是许嵩,否则输出蜀云泉真帅

    这个name变量,我如果在类里面写死的话,那么我想改只能改源码。所以写在配置文件web.xml里面

    先看看配置文件web.xml

        <servlet>
            <servlet-name>InitParamServlet</servlet-name>
            <servlet-class>main.com.vae.servletDemo.InitParamServlet</servlet-class>
            <init-param>
                <param-name>name</param-name>
                <param-value>许嵩</param-value>
            </init-param>
        </servlet>
    
        <!--向外暴露该Servlet类的一个资源名称,供外键直接访问,资源名称必须以 / 打头-->
        <servlet-mapping>
            <servlet-name>InitParamServlet</servlet-name>
            <url-pattern>/init</url-pattern>
        </servlet-mapping>

    和上面大差不差,只不过多了一个参数的<init-param>,里面是参数名和参数值。再看看类里面怎么获取的

    package main.com.vae.servletDemo;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import java.io.IOException;
    import java.util.Enumeration;
    
    public class InitParamServlet implements javax.servlet.Servlet{
    
        private ServletConfig config;
        public void init(ServletConfig servletConfig) throws ServletException {
            config=servletConfig;
        }
    
    
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            String name=config.getInitParameter("name");
            System.out.println(name);
            if ("许嵩".equals(name)) {
                System.out.println("是许嵩");
            }
            else{
                System.out.println("蜀云泉最帅");
            }
    
            //获取所有的参数的名称和值
            Enumeration<String> en=config.getInitParameterNames();
            while (en.hasMoreElements()) {
                String paramName=en.nextElement();
                System.out.println(paramName + "," + config.getInitParameter(paramName));
            }
    
        }
    
        public ServletConfig getServletConfig() {
            return null;
        }
    
    
        public String getServletInfo() {
            return null;
        }
    
        public void destroy() {
    
        }
    }

    HttpServletRequest接口常用的方法

    我的类是这样的

    package main.com.vae.day1;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.Enumeration;
    import java.util.Map;
    
    public class HttpServletRequestDemo extends HttpServlet {
    
        @Override
        public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println(req.getMethod());    //返回请求的方式:如Get/Post
            System.out.println(req.getRequestURI());//返回类型String,返回请求中的资源名字部分:如/req
            System.out.println(req.getRequestURL());//返回类型StringBuffer,返回请求浏览器地址栏中所有的信息
            System.out.println(req.getContextPath());//返回当前项目的上下文路径
            System.out.println(req.getRemoteAddr()); //返回请求客户机的IP地址
            String userAgent = req.getHeader("User-Agent");  //返回指定名称的请求头的值
            System.out.println(userAgent.contains("MSIE"));
            System.out.println(userAgent);
    
            System.out.println(req.getParameter("username"));//返回指定参数名的值
            String [] hobbys = req.getParameterValues("hobby");
            System.out.println(Arrays.toString(hobbys));  //返回指定参数名的多个值
            Enumeration<String> names=req.getParameterNames(); //返回所有参数名的Enumeration对象
            while (names.hasMoreElements()) {
                System.out.println("--->" + names.nextElement());
            }
    
            Map<String,String[]> paramMap=req.getParameterMap();//返回所有参数名的Map对象
            System.out.println(paramMap);
    
        }
    
    
    
    }

    浏览器这样输入

    http://localhost:8080/req?username=vae&hobby=java&hobby=girl&age=23

    结果

    HttpServletResponse接口常用的方法

    package main.com.vae.response;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @WebServlet("/resp")
    public class HttpServletResponseDemo extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置输出数据的MIME类型为html的,目的是输出的要以网页的格式展示
            //resp.setContentType("text/html");
            //设置编码格式为中文
            //resp.setCharacterEncoding("UTF-8");
    
            //上面的两行是必须写的,但是可以精简成一行,如下
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out=resp.getWriter();
            //在浏览器中输出一些内容
            out.println("Vae");
            out.println("许嵩");
            out.println("蜀云泉");
    
        }
    }

    servlet第一个页面,注册页面

    在webapp下面新建一个HTML文件,叫register.html,代码如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <h3>注册页面</h3>
        <form action="/regi" method="post">
            账号:<input type="text" name="userName" value="默认值" required><br/>   <!--required是Html5的新特性,在以前必填字段我们需要通过js来判断,现在html5实现!-->
            密码:<input type="password" name="passWord"><br/>
            性别:<input type="radio" name="sex" value="boy" checked="checked"/><input type="radio" name="sex" value="girl"/><input type="radio" name="sex" value="none"/>保密<br/>
            爱好:
            <input type="checkbox" name="hobby" value="Vae" checked="checked">许嵩
            <input type="checkbox" name="hobby" value="JJ" checked="checked">林俊杰
            <input type="checkbox" name="hobby" value="shuyunquan">蜀云泉<br/>
    
            城市:
            <select name="city"  size="1">  <!--size是一次显示几个,option加value就是值是什么,不加默认写的深圳-->
                <option value="sz">深圳</option>
                <option value="bj">北京</option>
                <option value="hn">河南</option>
            </select><br/><br/>
    
            自我介绍:
            <textarea name="intro" rows="5" cols="30"></textarea>  <!--这里textarea不能换行,必须写两个而且在同一行-->
            <br/><br/>
    
            <input type="submit" value="注册"/>
    
        </form>
    
    
    </body>
    </html>

     然后我们再新建一个Registerservlet的Servlet,以前我们每个Servlet都要去xml文件里面添加,很麻烦,所以我们这里使用注解。

    package main.com.vae.register;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Arrays;
    
    @WebServlet("/regi")
    public class RegisterServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String name=req.getParameter("userName");
            String passWord=req.getParameter("passWord");
            String sex=req.getParameter("sex");
            String city=req.getParameter("city");
            String intro=req.getParameter("intro");
            String[] hobbys=req.getParameterValues("hobby");
    
            System.out.println(name);
            System.out.println(passWord);
            System.out.println(sex);
            System.out.println(city);
            System.out.println(intro);
            System.out.println(Arrays.toString(hobbys));
    
        }
    }

    使用上面的 HttpServletRequest  的方法,我们可以接收到参数信息

    然后你会发现一个问题,中文乱码了

     解决中文乱码问题

     乱码的原因,因为Tomcat对get和post的请求,默认的都是采用 ISO-8859-1 的编码格式,而我们的中文是UTF-8的格式,所以编码不一样,肯定会出现乱码。

    解决方案如下:

     post方式很简单,直接输入req.setCharacterEncoding,设定一下编码格式就完事。如果是get方式,其实没必要,因为表单里面写get方式的话,参数都会在url里面显示的。所以采用get方式的时候一般都是查询,不会有参数的,有参数也是查询的参数,几乎没有中文。如果非要采用get传中文参数,可以修改Tomcat中的server.xml配置文件

     Servlet的映射细节

      每一个Servlet都可以在web.xml里面配置,这个配置的映射可以有很多可能

     

    这个是xml文件里面的,注解里面也可以这样写

    @WebServlet(value="/resp",
            initParams = {
            @WebInitParam(name="encoding",value = "utf-8"),
                    @WebInitParam(name="name",value = "许嵩")
            }
    )

    Servlet的配置xml和注解使用哪个?

    xml

    优点:一目了然,结构清晰

    缺点:每个Servlet都要配置xml,那100个就要写100次,代码重复,且造成xml文件的臃肿

    注解

    优点:简单,不臃肿

    缺点:和Java代码耦合在了一起,高耦合

    Servlet随服务器一起启动

    Servlet都是我们访问他们才会出结果。如果你想使得某一个Servlet随着服务器一起启动的话可以这样设置

    先看我的Servlet类吧

    package main.com.vae.day1;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    
    public class MappingServlet extends HttpServlet {
    
        public MappingServlet() {
            System.out.println("构造器");
        }
        @Override
        public void init(ServletConfig config) throws ServletException {
            super.init(config);
            System.out.println("初始化");
        }
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println(req.getMethod());
        }
    }

    xml配置方法:

    加一个load-on-startup就可以了,完美

        
        <servlet>
            <servlet-name>MappingServlet</servlet-name>
            <servlet-class>main.com.vae.day1.MappingServlet</servlet-class>
            <!--load-on-startup就是设置为启动服务器的时候启动这个Servlet,里面的数字越小,优先级越高-->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!--向外暴露该Servlet类的一个资源名称,供外键直接访问,资源名称必须以 / 打头-->
        <servlet-mapping>
            <servlet-name>MappingServlet</servlet-name>
            <url-pattern>/map</url-pattern>
        </servlet-mapping>
        

    注解的配置方法:

    先把我们上面的xml配置注释掉,看看注解的方式

    @WebServlet(value = "/map",loadOnStartup = 1)

    注解真的是好简单啊。。。

    Servlet的线程不安全问题

    在service方法里面这样写

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out=resp.getWriter();
            String name=req.getParameter("name");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            out.println("你输入的名字为:"+name);
    
        }

    然后你打开浏览器输入一个名字

    localhost/map?name=许嵩

    让别人也输入一个名字,或者你在3秒之内改一个名字,你发现,获取的不是许嵩了,这就是Servlet的线程不安全问题

     Servlet的缺点

    合并Servlet

    比如说我想写一个用户类的增删改查,难道我要写4个Servlet吗?那肯定是不行的,所以有了Servlet的合并,这样

     

    Servlet的上下文路径

    比如,我想访问某个Servlet,我要写    路径名称/Servlet名称  因为我们的path经常为空不写,所以在访问Servlet的时候也不写,万一我写path的名称了呢?我写一个aaa,那你代码里面访问Servlet必须加上aaa,我又突然修改了配置文件里面的path为bbb,难道你还要去改代码?所以我们使用上下文路径,就是上图,自动的去获取path的值。

  • 相关阅读:
    DTM DEM DSM 介绍
    VC自定义消息
    一句话设计模式基本原则
    抽空写了一个ICON图标的转换程序
    (转载)C# 中的委托和事件
    类的字段和静态字段的使用
    Command 对象总结
    使用 DataReader 检索数据的步骤
    分享一部电影
    C#处理ACCESS数据库
  • 原文地址:https://www.cnblogs.com/yunquan/p/10205386.html
Copyright © 2020-2023  润新知