JavaWeb第二讲

目录

二、Servlet详解

1、Servlet

1.1servlet的概念

1.2 servlet的继承关系

1.3Servlet访问

1.4 servlet方法处理请求响应

案例(绝对路径、相对路径):

1.5 转发和重定向

1.6 servletContext

二、Servlet详解

1、Servlet

1.1servlet的概念

Servlet是运行在服务端的小程序,用来处理客户端的请求并给予相应的java类。jsp文件相当于就是servlet文件。

1.2 servlet的继承关系

 

自定义的servlet是继承自HttpServlet的

1.2.1servlet接口

Servlet的框架是由两个Java包组成的:javax.servlet与javax.servlet.http。

1) 在javax.servlet包中定义了所有的Servlet类都必须实现或者扩展的通用接口和类。

init()、getServlet()、service()、getServlet()、destory()

2) 在javax.servlet.http包中定义了采用Http协议通信的HttpServlet类。

Servlet的框架的核心是javax.servlet.Servlet接口,所有的Servlet都必须实现这个接口

1.2.2 GenericServlet抽象类

自定义的Servlet需要通过实现Servlet接口来编写Servlet,但是我们每次都必须为Servlet中的所有方法都提供实现,还需要将ServletConfig对象保存到一个类级别的变量中,GenericServlet抽象类就是为我们省略一些模板代码,实现了Servlet和ServletConfig。

1.3Servlet访问

servlet无法通过类名直接访问servlet,需要通过映射的路径去访问(urlPatterns或者value),有两种方法:

1)通过urlPatterns注解方式访问

@WebServlet(name = "TestServlet", value = "/TestServlet",loadOnStartup = 1,initParams = {@WebInitParam(name = "driver",value = "com.mysql.cj.jdbc.driver")})

2) web.xml中配置路径映射

<servlet>
        &lt;!&ndash; 当地址栏请求之后,运行过程是111-222-333-444
        111:匹配要运行的映射路径
        222:找到要运行的映射文件名
        333:找到对应的文件名
        444:通过文件的绝对路径,找到要运行的文件 &ndash;&gt;
​
        &lt;!&ndash;333相当于注解方式的name字段,建议类名相同,但第一个字母小写&ndash;&gt;
        <servlet-name>testServlet</servlet-name>
        &lt;!&ndash;444servelt对应的:包名+类名&ndash;&gt;
        <servlet-class>com.lwl.controller.TestServlet</servlet-class>
        &lt;!&ndash;load-on-startup:该元素标记是否在servlet启动(init初始化)时就加载
        servlet初始化时就加载,中间的数字越小,优先级越高,
        配置时,数字要大于等于0的正整数,也可以为0
        若不配置,默认在servlet请求时才会加载&ndash;&gt;
        <load-on-startup>1</load-on-startup>
    </servlet>
    &lt;!&ndash;配置servlet的映射&ndash;&gt;
    <servlet-mapping>
        &lt;!&ndash;222一定要和上面的名字一样&ndash;&gt;
        <servlet-name>testServlet</servlet-name>
        &lt;!&ndash;111映射的路径&ndash;&gt;
        <url-pattern>/TestServlet</url-pattern>
    </servlet-mapping>
​
    &lt;!&ndash;可以写多个&ndash;&gt;
    <servlet>
        <servlet-name>testServlet2</servlet-name>
        <servlet-class>com.lwl.controller.TestServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    &lt;!&ndash;配置servlet的映射&ndash;&gt;
    <servlet-mapping>
        <servlet-name>testServlet2</servlet-name>
        <url-pattern>/TestServlet2</url-pattern>
    </servlet-mapping>
​

1.3.1 servlet工作原理

当Web服务器接收到一个HTTP请求时,它会先判断请求内容——如果是静态网页数据,Web服务器将会自行处理,然后产生响应信息;如果牵涉到动态数据,Web服务器会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例来处理,结果会送回Web服务器,再由Web服务器传回用户端。

Servlet是单例模式的: 针对同一个Servlet,Servlet容器会在第一次收到http请求时建立一个Servlet实例,然后启动一个线程(从容器线程池中获取一个)。第二次收到http请求时,Servlet容器无须建立相同的Servlet实例,而是启动第二个线程来服务客户端请求。所以多线程方式不但可以提高Web应用程序的执行效率,也可以降低Web服务器的系统负担。

1.3.2 servlet工作流程

1、Web Client 向Servlet容器(Tomcat)发出Http请求

2、Servlet容器接收Web Client的请求

3、Servlet容器创建一个HttpRequest对象,将Web Client请求的信息封装到这个对象中

4、Servlet容器创建一个HttpResponse对象

5、Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet对象

6、HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息

7、HttpServlet调用HttpResponse对象的有关方法,生成响应数据

8、Servlet容器把HttpServlet的响应结果传给Web Client

1.3.3 工作周期

Servlet生命周期,是指Servlet从加载、初始化、处理请求、返回响应、直到销毁的过程。

//@WebServlet(name = "TestServlet", value = "/TestServlet",loadOnStartup = 1)
//也可以在此直接配置参数,通过initParams来配置参数,在init方法中调用
@WebServlet(name = "TestServlet", value = "/TestServlet",loadOnStartup = 1,initParams = {@WebInitParam(name = "driver",value = "com.mysql.cj.jdbc.driver")})
public class TestServlet extends HttpServlet {
​
    //service服务可以调用很多次,用来处理各种请求的方法
    //service相当于doGet、doPost的集合体
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("GBK");
        PrintWriter writer = resp.getWriter();
        writer.print("hello");
        writer.flush();
        writer.close();
    }
​
    //初始化只调用一次
    @Override
    public void init() throws ServletException {
        //通过key值调用
        String driver = getInitParameter("driver");
        System.out.println(driver);
​
        System.out.println("初始化");
    }
    //servlet是单例模式,
    //创建servlet对象:
    //1、每次启动servlet容器,servlet会判断内存中是否有指定的servlet对象,如果没有则创建,如果有则创建Httprequest、Httpresponse对象,从而调用service方法
    //2、如果在web.xml文件或注解中指定了load-on-startup的值,则在servlet启动时,就会按照顺序创建并初始化servlet对象。
    //3、当servlet文件修改更新后,会重新创建servlet
    public TestServlet() {
        System.out.println("实例化");
    }
​
    //只销毁一次,当关闭servlet或者重启程序是调用销毁servlet的方法
    @Override
    public void destroy() {
        System.out.println("摧毁这个服务");
    }
}

servlet类2:

@WebServlet(name = "TestServlet2", value = "/TestServlet2" , loadOnStartup = 2)
public class TestServlet2 extends HttpServlet {
​
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
​
    }
​
    @Override
    public void init() throws ServletException {
        System.out.println("初始化222");
    }
    public TestServlet2() {
        System.out.println("实例化222");
    }
    @Override
    public void destroy() {
        System.out.println("摧毁这个服务222");
    }
}

通过观察load-on-startup存在和不存在的控制台情况,可以看到它的作用。

其中,在servlet运行过程中,在控制台tomcat会调用jdk的路径生成自己的文件路径,C:\Users\雷文林\AppData\Local\JetBrains\IntelliJIdea2022.2\tomcat\fe69fecd-5ad6-41f3-95ab-4978e8ca2575 里面存放了配置文件,日志,还有工作的servlet文件和jsp文件

1.3.4 配置初始化参数

1)通过web.xml文件配置中初始化

<servlet>
        <servlet-name>testServlet</servlet-name> 
        <servlet-class>com.lwl.controller.TestServlet</servlet-class>
        <init-param> 
            <param-name>driver</param-name> 
            <param-value>com.mysql.cj.jdbc.Driver</param-value> 
        </init-param> 
        <init-param> 
            <param-name>url</param-name> 
            <param-value>jdbc:mysql://localhost:3306/test?setverTimezone=Asia/Shanghai</param-value>
            </init-param> 
    </servlet> 
    <servlet-mapping> 
        <servlet-name>testServlet</servlet-name> 
        <url-pattern>/checkServlet</url-pattern> 
    </servlet-mapping>

2)通过注解方式初始化参数

@WebServlet(name = "TestServlet", value = "/TestServlet",loadOnStartup = 1,initParams = {@WebInitParam(name = "driver",value = "com.mysql.cj.jdbc.driver")})

获取初始化参数:要在初始化servlet时就调用参数

//初始化只调用一次,必须要在初始化的方法中调用
    @Override
    public void init() throws ServletException {
        //通过key值调用
        String driver = getInitParameter("driver");
        System.out.println(driver);
        System.out.println("初始化");
    }

1.4 servlet方法处理请求响应

对于每一个HTTP请求,servlet容器会创建一个封装了HTTP请求的ServletRequest实例传递给servlet的service方法,ServletResponse则表示一个Servlet响应,其隐藏了将响应发给浏览器的复杂性。

通过ServletRequest的方法你可以获取一些请求相关的参数,而ServletResponse则可以将设置一些返回参数信息,并且设置返回内容。

HttpServletResquest常用方法:
String getParameter(String); //根据名字获取参数的值:表单中的参数,地址栏中的参数
String[] getParameterValues(String);//根据名字获取一组参数的值(复选框)
Map<String,Object>[] getParameterMap()://获得一个Map<String, String[]>对象,所有的参数值都放在字符串数组中
getAttribute(String);//根据名字获取属性的值
setAttribute(String,Object);//根据属性设置值
getRequestDispatcher(String);//请求转发
setCharactorEncoding(); //设置编码方式
    
HttpServletResponse常用方法:
sendRirect();//重定向:重新请求指定的地址
setCharacterEncoding();//设置响应的编码方式;
addCookie(); //添加cookie
//所用登录界面为下面的.jsp文件
@WebServlet(name = "CheckServlet", value = "/checkServlet")
public class CheckServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置请求的编码格式
        req.setCharacterEncoding("utf-8");
        //获取表单中的元素,name="username",name属性的值一定要与表单元素的名字一致
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //判断得到的名字和密码是否正确
        if (username.equals("admin")&&password.equals("123456")){
            System.out.println("登录成功");
​
            //根据属性设置值,将值存储到request中
            req.setAttribute("user",username);
            //指明请求转发的路径
            RequestDispatcher requestDispatcher = req.getRequestDispatcher("/SecondServlet");
            //请求转发,将值通过request转发,与接收值的一方共用一个request及里面的值
            requestDispatcher.forward(req,resp);
        }else{
            System.out.println("登陆失败");
            //假如映射路径是双层路径,那么在使用重定向时,重定向只会更换最后一个/后的内容,
            //如果登陆失败,是跳不回登录界面的,
            // 有两种解决方案
            // 1、使用../index.jsp返回上级目录,就能顺利跳回登录界面
            // 登录失败后路径http://localhost:8080/JavaWebDay02_war_exploded/index.jsp
            //2、把项目名称改为只剩一个/,对于双层路径这样的话用绝对路径也能顺利跳回登录界面
​
            //而对于单层路径,无论是相对路径还是绝对路径都可以调回登录界面
            resp.sendRedirect("index.jsp");
        }
    }
}

案例(绝对路径、相对路径):

登录界面(.jsp):

 <%--
  对于单层路径而言
  加斜杠(404 not found)绝对路径:http://localhost:8080/checkServlet
  绝对路径:相对于localhost:8080而言的
  不加斜杠/  相对路径:http://localhost:8080/JavaWebDay02_war_exploded/checkServlet
  相对路径:是相对于当前的项目 localhost:8080/项目名字/映射路径
  --%>
<form action="UserServlet" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
  </form>

实体类:

public class User {
    private Integer id;
    private String username;
    private String password;
​
    public Integer getId() {
        return id;
    }
​
    public void setId(Integer id) {
        this.id = id;
    }
​
    public String getUsername() {
        return username;
    }
​
    public void setUsername(String username) {
        this.username = username;
    }
​
    public String getPassword() {
        return password;
    }
​
    public void setPassword(String password) {
        this.password = password;
    }
}

接口及实现类

public interface IUserDao {
    List<Map<String,Object>> findOne(User user);
}
​
public class UserDaoImpl extends BaseDao implements IUserDao {
    
    @Override
    public List<Map<String,Object>> findOne( User user) {
        String sql = "select * from user where username=? and password=?";
        List<Map<String, Object>> query = query(sql, user.getUsername(), user.getPassword());
        return query;
    }
}
 

检查登录界面:

@WebServlet(name = "UserServlet", value = "/UserServlet")
public class UserServlet extends HttpServlet {
​
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       IUserDao iUserDao = new UserDaoImpl();
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        List<Map<String, Object>> one = iUserDao.findOne(user);
        if (one.size()>0){
            req.setAttribute("user1",username);
            RequestDispatcher requestDispatcher = req.getRequestDispatcher("/SecondServlet");
            requestDispatcher.forward(req,resp);
​
            resp.sendRedirect("/SecondServlet");
            System.out.println("登录成功");
        }else {
            resp.sendRedirect("/index.jsp");
        }
    }
}

书城(接收数据):

@WebServlet(name = "SecondServlet", value = "/SecondServlet")
public class BookServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
​
        IBookDao iBookDao = new BookDaoImpl();
        List<Map<String, Object>> all = iBookDao.findAll();
        response.setCharacterEncoding("GBK");
        PrintWriter writer = response.getWriter();
//接收request中传来的数据
        //通过request获取里面存放的元素,
        Object user = request.getAttribute("user1");
        writer.print("<html><body>");
        writer.print("<span>欢迎您,"+user+"</span>");
​
        writer.print("<table border='1' rules=all > "+
                "<tr><td>id</td><td>bookname</td><td>price</td><td>author</td></tr>");
        int size = all.size();
        for (int i = 0; i < size; i++) {
            writer.print("<tr>");
            writer.print("<td>"+all.get(i).get("id")+"</td>");
            writer.print("<td>"+all.get(i).get("bookname")+"</td>");
            writer.print("<td>"+all.get(i).get("price")+"</td>");
            writer.print("<td>"+all.get(i).get("author")+"</td>");
            writer.print("</tr>");
        }
        writer.print("</table>");
        writer.print("</body></html>");
        writer.flush();
        writer.close();
​
    }
​
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
​
        this.doGet(request,response);
    }
}

1.5 转发和重定向

1.5.1 转发和重定向区别

服务器转发:发出了一次请求,地址栏不发生变化。可以携带数据,在服务器端完成,效率高且安全

携带数据可以在Servlet之间进行传递

//请求转发,服务器转发
request.setAttribute("msg","欢迎你登陆成功");//request存储数据
request.getRequestDispatcher("/welcomeServlet").forward(request,response);

客户端重定向:发出了两次请求,地址栏发生变化,不可以携带数据

客户端重新发送新的请求。

//客户端重定向
//服务器会向客户端浏览器发送一个响应:url, 客户端会重新请求该URL
request.setAttribute("msg","欢迎你登陆成功");//request存储数据
response.sendRedirect("/login.html");

1.6 servletContext

ServletContext是代表了Servlet应用程序。每个Web应用程序只有一个context。在分布式环境中,一个应用程序同时部署到多个容器中,并且每台Java虚拟机都有一个ServletContext对象。

servletcontext对象就相当于是一个全局变量域,当在这个应用存在的时候,里面的内容会一直存在。

1.6.1 获取servletContext内容

先声明一个变量放在servletcontext内容中:

可以通过配置文件,也可以通过注解方式

   <context-param>
        <param-name>gongfu</param-name>
        <param-value>太极拳</param-value>
    </context-param>

设置内容:

 ServletContext servletContext = this.getServletContext();
        String gongfu = servletContext.getInitParameter("gongfu");
        System.out.println(gongfu);
        servletContext.setAttribute("gf",gongfu);

获取内容:

  ServletContext servletContext = this.getServletContext();
        Object gf = servletContext.getAttribute("gf");
        System.out.println("========="+gf);

配置好内容后,必须要先执行设置内容的程序,再执行获取内容的程序才能取到值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值