Servlet(1)

目录

一、serverlet获取参数

二,汉字乱码

 四、servlet生命周期

五、HTTP协议

六、session会话

七、服务器内部转发及客户端重定向

八、Thymeleaf-视图模板技术

九、保存作用域

十、路径问题

        Tomcat免费、体积小。tomcat目录结构:

        bin:可执行文件目录;conf:配置文件目录;lib:存放lib的目录;logs:日志文件目录;webapps:项目部署的目录;work:工作目录;temp:临时目录。部署在tomcat上的项目,客户端通过网址进行访问,每个项目的context root不一样。

        在IDEA中部署web项目的时候,实际上是部署在web文件夹下。实际上部署在服务器上的是artifact包。如果在IDEA中创建一个普通java项目后,需要在模块中添加web,创建artifact包。

一、serverlet获取参数

        在网页上输入信息,最终通过服务器上传到数据库,大致思路如下:1,客户端发送请求,action=add; 2,在xml文件中的servlet-mapping中对应的映射关系里,找到add,其对应的servlet-name是addConnection 3,然后找到addConnection对应的类com.myWeb.serverlet.AddServerlet 4,因为发送的是post请求(method=post),tomcat会执行类中的doPost方法;5,最后利用JDBC将数据上传到数据库。

        为了使请求得到正确的处理,对WEB-INF文件夹下的web.xml加入如下的servlet代码。

 <servlet>
    <servlet-name>addConnection</servlet-name>
    <servlet-class>com.myWeb.serverlet.AddServerlet</servlet-class>
</servlet>
    <servlet-mapping>
        <servlet-name>addConnection</servlet-name>
        <!--记得一定要加action前面的/-->
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

        前端的网页如下所示:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>fruit</title>
</head>
<body>
<form action="add" method="post">
    名称:<input type="text" name="name"/><br/>
    数量:<input type="text" name="num"/><br/>
    价格:<input type="text" name="price"/><br/>
    提交:<input type="submit" value="添加">
</form>
</body>
</html>

        处理收到请求的doPost方法如下:

//HttpServlet在tomcat里面,需要对项目添加依赖
public class AddServerlet extends HttpServlet {

    @Override
    //重写HttpServlet中的doPost方法,处理post请求
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //对于客户端发过来的请求,服务器就将其封装成一个请求req,然后通过getParameter方法获取发送过来的name
        String name=req.getParameter("name");
        //因为http发送过来的信息只能是String,所以通过包装类的方法进行转换
        String numStr=req.getParameter("num");
        Integer num=Integer.parseInt(numStr);
        String priceStr=req.getParameter("price");
        Integer price=Integer.parseInt(priceStr);

       //利用JDBC将数据上传到数据库
        int count=InsertFruit.insertData(name,num,price);
        System.out.println(count);
    }
}

Notations:

(1)在配置JDBC的jar包时,不能像普通java项目那样配置,必须配置到WEB-INF下面的lib包。如果lib文件夹不在WEB-INF下,也可以通过ProjectSetting下的Problem点击fix选择add to...。不然jar包实际上没有添加到artifact部署包上。:

 (2)部署项目时,修改application context,然后回到server选项卡,需要检查项目运行时默认运行的URL的值,可能会不正确,启动后报错404(找不到指定资源)。如果不修改网址,默认访问的是web下的index html/htm/jsp文件,如果写了其他文件就不行。我们也可以通过web.xml对此进行设置。

(3)如果网页出现405问题,表明当前请求的方法不支持。servlet中必须对应doPost,那么请求方法只能post。

二,汉字乱码

        tomcat8之后如果是get请求发送的中文数据不需要设置编码。在tomcat8之前的get请求自身没有设置编码方式的方法,需要把获得的字符串转成byte[]数组,再转UTF-8,最后重新拼接成字符串。对于post请求,需要设置编码方式为UTF-8,就不会出现中文乱码。

//设置req的编码方式
        req.setCharacterEncoding("UTF-8");

   Notations:设置编码方式需在设置所有参数之前

三、servlet继承关系

        关系示意图:

        

        HttpServlet也是一个抽象类,需要继承实现。

        常用方法:在servlet接口有:

        void init(config) -初始化方法

        void service(request,response) -服务方法

        vodi destory()  -销毁方法

        GenericServlet实现了init()和destroy()方法,但GenericServlet中的service方法仍然是抽象的。而在HttpServlet中不再是抽象的。部分service源码:


         可见根据请求方式的不同service方法中会调用不同的方法响应。 

Notations:当有请求时,service方法会自动响应(实际上由tomcat服务器调用)。在HttpServlet中会分析请求的方式,调用相应的do开头的方法。而这些do方法如果子类没有实现,那么它们会报405错误,如下所示。因此,新建Servlet时,需要考虑请求方法,再决定重写哪个do方法。

 四、servlet生命周期

        (1)生命周期:从出生到死亡的过程。对应servlet中三个方法:init(),service(),destroy()

        (2)默认情况下,第一次请求时,servlet会进行实例化,初始化,然后服务。从第二次请求开始,每一次都只有服务。当容器关闭时,其中所有的servlet实例都会被销毁。这样可以提高系统的启动速度。但是第一次请求时耗时较长。

        因此如果要提高系统的启动速度,servlet的l默认情况就可以。但如果要提高响应速度,应该设置servlet的初始化时机。

        (3)servlet的初始化时机:可以通过在xml文件的<servlet>标签中加上<load-on-startup>标签来设置初始化的时候。标签中写入一个数值,数值越小时机越靠前(最小值0)。

        如:

        <servlet-name>test</servlet-name>
        <servlet-class>com.myWeb.serverlet.LifeTime</servlet-class>
        <load-on-startup>1</load-on-startup>

        在第一次请求发送前,就已经初始化了:

         servlet在容器中是单例的、线程不安全的。它只会创建一个实例对所有的请求作出响应。线程不安全举例如下:

         如果线程1是访问线程,需要num值进行路径判断。而线程2对num值进行修改,可能导致线程1的访问路径改变。

Notations:尽量不要在servlet中定义成员变量。如果定义了,不要去根据变量值进行逻辑判断,不要修改它的值。

五、HTTP协议

        Http即超文本传输协议。HTTP是无状态的。HTTP请求响应包括请求和响应两个部分。请求包含三个部分:1,请求行;2,请求消息头;3,请求主体。

Notations:无状态指服务器无法判断发送请求的客户端。

        请求行包含三个部分:请求方式(get,post,etc);访问地址;HTTP的协议版本。如下:

                POST/dynamic/target.jsp HTTP/1.1

        而请求的消息头就是包含了请求的具体参数,包括如下的键值对:

         请求体分为三种情况:

(1)get方式没有请求头,但是有一个queryString(查询字符串);

(2)post方式有请求头,form data;

(3)json格式有,叫request playload

        响应也包含三个部分,类似的有:1,响应行;2,响应头;3,响应体。

        响应行包含三个信息:HTTP协议版本;响应状态码;响应状态。如:

                HTTP/1.1 200 ok

Notations:常见的响应状态码:200:正常响应;404:找不到资源;405:请求方式不支持;500:服务器内部错误。

        响应头:包含了服务器发送给浏览器的信息(内容媒体信息、编码、内容长度等)

                

         响应体:响应的实际内容。比如请求的html文件里的内容。

六、session会话

        由于HTTP是无状态的,会导致发生混乱。比如添加商品到购物车和结账两次请求。而通过会话跟踪技术可以解决这个问题。

(1)会话跟踪技术

        如果一个客户端第一次发送请求给服务器,服务器发现没有请求没有会话ID,服务器就会分配一个给它。下次请求服务器就能分辨出这个客户端。常用的API:

request.getSession();
//获取当前会话,没有创建一个新的
request.getSession(false);
//获取当前会话,没有返回NULL,不创建新的,参数为true和不带参数一样

//request获取的对象为session,获取sessionID
session.getID();
//判断当前会话是否是新的
session.isNew();
//获取session的非激活间隔时长,默认半小时
//设置该时长
session.getMaxInactiveInterval();
session.setMaxInactiveInterval();

   (2)session保存作用域

        当获取到会话对象session后,可以通过setAttribute方法向保存作用域保存一个数据。保存的位置是服务器的内存里。

//保存数据lina,对应的key为uname
session.setAttribute("uname","key");
//获取这个数据
session.getAttribute("uname");
//删除session
session.removeAttribute();

        在作用域里存放的数据是跟会话绑定的,当其他客户端进行请求的时候,获取不了这个数据。举例说明:

        分别写两个执行service方法的servlet类,并进行配置:

//设置一个作用域
public class Session extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession hs=req.getSession();
        hs.setAttribute("key","name");
    }
}

//获取上次访问的作用域中保存的数据
public class Session1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getSession().getAttribute("key"));
    }
}

//进行配置
 <servlet>
        <servlet-name>Session</servlet-name>
        <servlet-class>com.myWeb.serverlet.Session</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Session</servlet-name>
        <!--记得一定要加action前面的/-->
        <url-pattern>/session</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>Session1</servlet-name>
        <servlet-class>com.myWeb.serverlet.Session1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Session1</servlet-name>
        <!--记得一定要加action前面的/-->
        <url-pattern>/session1</url-pattern>
    </servlet-mapping>

        使用谷歌浏览器,第一次访问http://localhost:8080/web_war_exploded/session,第二次访问http://localhost:8080/web_war_exploded/session1。可以成功获取到数据。

        然后使用IE浏览器访问http://localhost:8080/web_war_exploded/session1,得到的是null,因为更换浏览器导致会话改变。

七、服务器内部转发及客户端重定向

       服务器内部转发和客户端重定向使用的代码:

//内部转发 
req.getRequestDispatcher("...").forward(req,resp);
//重定向 
resp.sendRedirect("...");

        服务器内部转发可以把一个请求从一个servlet转发给另一个servlet。如下所示:

         客户端重定向,是服务器响应让客户端自己向另一个组件发请求。如下所示:

         使用上述两种方式进行相同的操作,服务器内部转发最后客户端只进行了一次请求,而客户端重定向需要客户端发送两次请求。

八、Thymeleaf-视图模板技术

        将数据库中获得的数据和静态的网页页面相结合的过程,称之为渲染(render)。Tymeleaf可以帮助进行视图渲染。

        可以使用注解为请求配置相应的servlet,不用在web.xml文件中说明,如下所示:

//从servlet3.0开始支持注解方式的注册
@WebServlet("/get")
public class GetServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Fruit> l=new ArrayList<Fruit>();
        //利用JDB获得数据库中的数据,并将每行数据封装成一个Fruit类
        l=GetFruit.getFruit();
        for(Fruit f:l){
            System.out.println(f);
        }
        //创建会话并将Fruit类的ArrayList保存在保存域里面
        HttpSession hs=req.getSession();
        hs.setAttribute("FruitList",l);
    }
}

        使用thymeleaf需要添加thymeleaf的jar包。新建的servlet类需要继承ViewBaseServlet。其代码如下:

package com.myWeb.serverlet;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
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 ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

        然后需要在web.xml文件中添加配置,如下所示:

<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<context-param>
    <param-name>view-prefix</param-name>
    <param-value>/WEB-INF/view/</param-value>
</context-param>
<context-param>
    <param-name>view-suffix</param-name>
    <param-value>.html</param-value>
</context-param>

        <context-parm>叫做配置上下文参数。prefix:前缀;suffix:后缀。第一个param-value也可以写成/,代表根目录WEB-INF。在ViewBaseServlet类中会调用这两个参数。

        接着创建一个类继承ViewBaseServlet。因为ViewBaseServlet继承了HttpServlet,所以新类也是一个servlet。然后使用ViewBaseServlet中的processTemplate函数将逻辑视图对应到基础视图上,如下:

//从servlet3.0开始支持注解方式的注册
@WebServlet("/index")
public class GetServlet extends ViewBaseServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Fruit> l=new ArrayList<Fruit>();
        //利用JDB获得数据库中的数据,并将每行数据封装成一个Fruit类
        l=GetFruit.getFruit();
        //创建会话并将Fruit类的ArrayList保存在保存域里面
        HttpSession hs=req.getSession();
        hs.setAttribute("FruitList",l);

        //此处的视图名称是Fruit
        //下面的函数会将逻辑视图Fruit名称对应到物理视图名称上去
        //物理视图名称是 view-prefix+逻辑视图名称+view-suffix
        //而这三者分别对应 /             index       .html
        super.processTemplate("index",req,resp);
    }
}

        使用thymeleaf进行渲染需要修改index.html页面。thymeleaf的一些常用标签:

        th:if      th:unless       th:each        th:text

        使用thymeleaf将session中保存的集合渲染到静态页面上:

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="2.css">
</head>
<body>
<div id="div_container">
    <div id="div_fruit">
        <table id="tb_fruit">
            <tr>
                <th>水果</th>
                <th>数量</th>
                <th>单价</th>
            </tr>
            <!--用thymeleaf的语法写的分支语句,没有读到session里的数据就进行合并-->
            <tr th:if="${#lists.isEmpty(session.FruitList)}">
                <td colspan="3">库存为空</td>
            </tr>
            <!--设置一个临时变量fruit去获得集合FruitList里面的数据-->
            <tr th:unless="${#lists.isEmpty(session.FruitList)}" th:each="fruit:${session.FruitList}">
                <td th:text="${fruit.name}">苹果</td>
                <td th:text="${fruit.num}">2</td>
                <td th:text="${fruit.price}">5</td>
            </tr>
        </table>
    </div>
</div>
</body>
</html>

  Notations:<html>标签要加上

xmlns:th="http://www.thymeleaf.org"才能使用thymeleaf;

九、保存作用域

        保存的作用域一般有四个:page(基本不用)、request(一次请求响应)、application(整个应用程序)还有之前的session.

       session在一次会话里生效,在同一个客户端多次发送请求,都可以获得这个session。而request只在一次请求中生效。比如如果使用客户端重定向,两次请求就获得不了一样的request。

而application在一次应用程序都生效,不同客户端发送请求都可以获得application。获得application的方式:

  ServletContext application=req.getServletContext();

        ServletContext称为Servlet的上下文环境,当服务启动,它就确定了。

十、路径问题

               

        ../表示返回上一级目录。比如上图中,如果user文件夹下的login.html想要引用css文件夹下的login.css文件,使用相对路径:"../css/login.css"。

        但在开发中,绝对路径使用较多,例如服务器部署在本机上login.css的绝对路径"http://localhost:8080/pro10/css/index.css"。
        可以添加一个基础绝对路径:

<base href="http://localhost:8080/pro10/"/>
//页面上所有路径都以此为基础
//login.css的绝对路径可以改为
<link href="css/login.css">

        在thymeleaf中,可以这样写:

th:href="@{}"
//根路径
<link href="@{/css/login.css}">

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值