Servlet(一)

Servlet组件

什么是servlet

Servlet是一种用于扩展服务器功能的服务器端组件技术,用于实现动态网页编程

  • 是直接或者间接实现Servlet接口的类
  • 有三种:Servlet Filter xxxListener

Hello Servlet

Servlet接口不在JavaSE中,需要因为servlet-api依赖

 <dependency>
     <groupId>javax.servlet</groupId>
     <artifactId>javax.servlet-api</artifactId>
     <version>4.0.1</version>
     <scope>provided</scope>  scope=provider表示该jar包在编译阶段使用,并不会打包到应用中
</dependency>

1、定义一个类实现Servlet接口

public class HelloServlet implements Servlet {  //所谓的Servlet就是直接或者间接的实现Servlet接口
    @Override
    public void init(ServletConfig config) throws ServletException {
    }
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {   // Servlet组件用于对外提供服务的方法
        //接收用户提交数据,不管是使用get还是post提交
        String username=req.getParameter("username");
        if(username==null ||username.trim().length()<1)
            username="Servlet";
        String message="Hello "+username+"!";
        //使用rep生成针对客户端请求的响应信息
        PrintWriter pw=res.getWriter();
        pw.println("<h2>"+message+"</h2>");//生成html文档
        pw.flush();
        pw.close();
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
    }
}

service方法实际上是由tomcat服务器负责调用执行,服务器调用方法时会传入两个参数,一个req用于封装所有的用户请求信息,一个res用于封装服务器向客户端的响应信息

  • req.getParameter用于获取用户提交的数据,例如get请求 hello.do?username=zhangsan

  • res.setContentType用于告知客户端的浏览器,如何处理响应信息

    • res.setContentType(“text/html;charset=utf-8”);
    • 遵循一个MIME协议(多用途互联网邮件协议),其中text表示是一个文本文档,html表示是一个html格式的文档文档
  • res.getWriter用于获取向客户端输出数据的输出流,在编码中向输出流中写出数据,实际上就是向客户端输出的内容

2、在web应用的核心配置文件web.xml中将Servlet和一个URL地址建立对应关系,当用户请求对应的URL地址时则触发Servlet运行

  • Servlet类中没有main方法,所以程序的执行是由服务器按照规则进行调用的
  • 由客户端对特定路径发起请求触发执行
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 将Servlet类和一个名称建立对应关系 -->
    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.yan.action.HelloServlet</servlet-class>
    </servlet>
    <!-- 将一个地址和名称建立对应关系 -->
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello.do</url-pattern>
    </servlet-mapping>
</web-app>

3、启动Tomcat服务器

4、在浏览器中输入请求URL地址 http://localhost:8080/demo1_war/hello.do

5、使用get提交数据 http://localhost:8080/demo1_war/hello.do?username=zhangsan

IDEA控制台提示乱码

在Tomcat服务器下conf/logging.properties是日志输出的相关配置

java.util.logging.ConsoleHandler.encoding = GBK

Servlet的特点

Servlet用MIME过滤数据,由javax.servlet和javax.servlet.http两个包组成Java Servlet API框架

编写Servlet必须直接或间接实现作为Servlet的核心javax.servlet.Servlet接口,通常是实现javax.servlet.http.HttpServlet的子类,可以覆盖继承doGet()或者doPost()方法,两者分别对应于Http(s)中的Get请求和Post请求。

优点
  • 可以移植性:由于Servlet是用Java语言编写的,因此它可以在不同的操作系统和服务器上移植
  • 安全:Servlet具有类型检查特征,并利用Java的垃圾收集和没有指针的设计,使得Servlet避免了内存管理等问题
  • 高效:Servlet加载执行后会常驻服务器内存中,当再次受到客户端的请求时,服务器会产生新的线程而不是进程为客户端服务,这样就提高了响应速度。 – Java是最差的内存性价比

缺点

  • 不能所见即所得开发
  • 生成html文档需要通过一系列的输出完成,非常的繁琐低效
应用场景

主要是处理客户端的请求并将其结果发送到客户端 ,由于生成html文档繁琐低效,所以一般不建议使用Servlet直接生成响应页面。建议考虑使用JSP

Servlet开发

Servlet编程

  • 直接实现Servlet接口,需要实现5个方法

    public interface Servlet {
       public void init(ServletConfig config) throws ServletException;  //servlet对象创建后执行初始化操作,例如通过config读取配置信息
       public ServletConfig getServletConfig();  //获取当前Servlet对象的相关ServletConfig对象。ServletConfig对象用于封装当前Servlet对象的配置信息
       public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;  //对外提供服务。Servlet针对多用户会采用单实例多线程的方式对外提供服务
       public String getServletInfo();  //获取当前Servlet的说明信息,一般供工具使用
       public void destroy(); //在当前Servlet实例被GC回收前所运行的方法,一般用于资源回收
    }
    
  • 为了简化开发,所以Sun提供了一个通用抽象父类GenericServlet。针对大部分方法提供了默认的空实现,只需要Servlet提供service方法的实现即可,一般用于非通用协议开发中。采用的是适配器模式

    public class Hello3Servlet extends GenericServlet {
        @Override
        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
    
        }
    }
    
  • 为了进一步简化开发,提供针对http协议的支持,Sun提供了一个GenericServlet的子类HttpServlet,这个父类专门用于http协议的应用开发中,是模板设计模式

    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
            String method = req.getMethod();   //获取客户端的请求方法,例如get/post之类
            if (method.equals(METHOD_GET)) {  //如果是GET请求则调用doGet方法
               ...
                    doGet(req, resp);   //转向调用自己的doGet方法
            } else if (method.equals(METHOD_HEAD)) {
                doHead(req, resp);
            } else if (method.equals(METHOD_POST)) {
                doPost(req, resp);
            } else if (method.equals(METHOD_PUT)) {
                doPut(req, resp);
            } else if (method.equals(METHOD_DELETE)) {
                doDelete(req, resp);
            } else if (method.equals(METHOD_OPTIONS)) {
                doOptions(req,resp);
            } else if (method.equals(METHOD_TRACE)) {
                doTrace(req,resp);
            } else {  //如果是其它请求方法则报错
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[1];
                errArgs[0] = method;
                errMsg = MessageFormat.format(errMsg, errArgs);
                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
            }
        }	
    

默认的doGet方法实现

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException  {
        String protocol = req.getProtocol();  //获取请求所使用的协议,例如http/1.1
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

###Servlet的三生命周期

  • 默认servlet不会自动加载,只有当第一次访问时才会被服务器自动加载,一般Servlet会采用单实例多线程的方式对外提供服务

  • 加载完成立即执行初始化操作(new操作),构建对象完成后立即执行init方法,同时服务器会将当前Servlet的配置信息封装在一个ServletConfig对象中 。在一个Servlet的生命周期过程中init方法执行且只执行一次

    <servlet>
            <servlet-name>hello2Servlet</servlet-name>
            <servlet-class>com.yan.action.Hello2Servlet</servlet-class>
            <!--初始化配置参数胡-->
            <init-param>
                <param-name>name</param-name>
                <param-value>lisi</param-value>
            </init-param>
    </servlet>
    
  • 针对用于请求信息以多线程的方式运行service方法,同时服务器会自动封装request和response对象传入方法中

  • 请求处理完毕,Servlet对象常驻内存。

  • 只有当关闭服务器或者由于内存不足导致当前Servlet对象被调度销毁对象时,才会执行destroy方法,在一个Servlet的生命周期过程中destroy方法执行且只执行一次

###练习:用户登录

流程:

地址栏中输入/login.do打开输入页面,供用户输入对应的用户名和口令,再点击提交按钮则再服务器中执行数据库查询验证,成功则显示欢迎页,否则报错

  • 地址栏中输入地址----Get请求
  • 点击提交按钮,因为涉及敏感数据—Post提交

开发:

public class LoginServlet extends HttpServlet {
    //针对get请求的处理,需要生成一个带有form表单的输入页面
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out=resp.getWriter();
        out.println("<html><head><title>用户登录</title></head><body>");
        out.println("<form><table>");
        out.println("<tr><td>用户名称:</td><td><input name=‘username’/></td></tr>");
        out.println("<tr><td>用户口令:</td><td><input type='password' name=‘passwird’/></td></tr>");
        out.println("<tr><td colspan=2><input type='submit' value='登录系统'/><input type='reset' value='重置数据'/></td></tr>");
        out.println("</table></form>");
        out.println("</body></html>");
    }
}

配置web.xml

    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>com.yan.action.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login.do</url-pattern>
    </servlet-mapping>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXbyHcYp-1618486504386)(images/login页面.png)]

点击提交按钮的处理

  • 如果针对<form>表单不设置method,则默认采用get请求;

    • http://localhost:8080/demo1_war/login.do?username=adfasd&password=adfasd
    • 如果定义一个<form>没有action,则提交到当前页面
  • 如果需要使用post提交,则必须设置method=post

package com.yan.action;

import com.yan.util.JdbcUtil;

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.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;

public class LoginServlet extends HttpServlet {
    //针对get请求的处理,需要生成一个带有form表单的输入页面
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {   //对应get请求的具体处理
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out=resp.getWriter();
        out.println("<html><head><title>用户登录</title></head><body>");
        out.println("<form method='post'><table>");
        out.println("<tr><td>用户名称:</td><td><input name='username'/></td></tr>");
        out.println("<tr><td>用户口令:</td><td><input type='password' name='password'/></td></tr>");
        out.println("<tr><td colspan=2><input type='submit' value='登录系统'/><input type='reset' value='重置数据'/></td></tr>");
        out.println("</table></form>");
        out.println("</body></html>");
    }
    //针对post请求的处理,需要调用数据库查询判断用户提交的数据是否正确
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  //针对post请求的具体处理,目前可以实现post请求的方法只有一种<form method=post>
        String username=req.getParameter("username");  //获取用户在<input name="username"/>输入框中输入的数据
        String password=req.getParameter("password");
        boolean bb=false;
        //这里实际上就是登录处理逻辑,直接写在Servlet类中是不合理的,应该参照JavaEE的三层开发的方式来实现
        Connection conn=null;
        ResultSet rs=null;
        JdbcUtil ju=JdbcUtil.getInstance();
        try{
            conn= ju.getConnection();
            String sql="select * from t_users where username=? and password=?";
            rs=ju.executeQuery(conn,sql,username,password);
            bb=rs.next();
        }catch(Exception e){
            throw new ServletException(e);
        }finally{
            try {
                ju.close(rs,null,conn);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out=resp.getWriter();
        if(bb){
            //成功页
            out.println("success!");
        }else{
            //失败页
            out.println("failure!");
        }
        out.flush();
        out.close();
    }
}

注意:需要在MySQL中创建一个数据库和对应的数据表,表中包含数据才能登录成功


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值