Java教程

JavaWeb技术:Tomcat、servlet

本文主要是介绍JavaWeb技术:Tomcat、servlet,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录

Tomcat:web服务器软件

Servlet:运行在服务器端的小程序 

Servlet的执行原理

Servlet中的生命周期方法

init(创建):只执行一次

service(提供服务):执行多次

@WebServlet注解

servlet的体系结构

http:超文本传输协议

请求消息数据格式

响应消息数据格式

Request

获取请求消息

获取请求行的相关方法

获取请求头的相关方法

获取请求体数据

获取请求的通用方法

中文乱码问题

请求转发

共享数据

获取ServletContext

BeanUtils工具类,简化数据封装

Response

设置响应信息

设置响应行

设置响应头

设置响应体

重定向(redirect)

乱码问题

补充知识

响应状态码

路径写法

ServletContext对象

获取方法

其它方法


Tomcat:web服务器软件

服务器:安装了服务器软件的计算机

web服务器软件:接收用户的请求,处理请求,做出响应,可以部署web项目

基本操作

  • 软件启动:startup.bat ,运行该文件即可
  • 正常关闭:shutdown.bat,运行该文件即可
  • 强制关闭:点击启动窗口的X

部署项目的方式

  • 直接将项目放到webapps目录下即可
    • 简化部署:将项目打成一个war包(.war文件),再将war包放置到webapps目录下 war包会自动解压缩
  • 配置conf/server.xml文件(tomcat核心配置文件)
    • 在<Host>标签体中配置  <Context docBase=" "  path=" ">  
      • docBase:项目存放的路径 (文件夹的路径)
      • path:虚拟路径
      • 访问时,ip:端口号/虚拟路径/项目内的文件名
    • <Context docBase="D:\test" path="/aaa"/>
  • 在conf/Catalina/localhost创建任意名称的xml文件,在文件中编写 <Context docBase=" ">
    • 访问时的虚拟目录就是xml的文件名

java动态项目的目录结构

                        -- 项目的根目录
                            -- WEB-INF目录:
                                -- web.xml:web项目的核心配置文件
                                -- classes目录:放置字节码文件的目录
                                -- lib目录:放置依赖的jar包

Servlet:运行在服务器端的小程序 

Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。将来我们自定义一个类,实现Servlet接口,复写方法(遵守规则,tomcat才会运行它)

Servlet的执行原理

       1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
        2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
        3. 如果有,则在找到对应的<servlet-class>全类名
        4. tomcat会将字节码文件加载进内存,并且创建其对象
        5. 调用其方法

Servlet中的生命周期方法

init(创建):只执行一次

在<servlet>标签下配置创建时机

  • <load-on-startup>的值为负数 第一次被访问时,创建(默认)
  • <load-on-startup>的值为0或正整数  在服务器启动时,创建

Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值

service(提供服务):执行多次

每次访问Servlet时,Service方法都会被调用一次

destroy(被销毁):只执行一次

  • 只有服务器正常关闭时,才会执行destroy方法
  • 一般用于销毁资源

@WebServlet注解

可以不用创建web.xml,在类上使用该注解进行配置

servlet的体系结构

        Servlet -- 接口
            |
        GenericServlet -- 抽象类
            |
        HttpServlet  -- 抽象类

  • GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
  • HttpServlet:对http协议的一种封装,简化操作,复写doGet/doPost
    • service方法会先判断传输方式(get、post),再调用其方法

urlpartten:servlet访问路径

一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})

路径定义规则

  • /xxx:路径匹配
  • /xxx/xxx:多层路径,目录结构
  • *.do:扩展名匹配(可以是任意的后缀名称)

http:超文本传输协议

定义了,客户端和服务器端通信时,发送数据的格式

特点

  • 基于TCP/IP的高级协议
  • 默认端口号:80
  • 基于请求/响应模型的:一次请求对应一次响应
  • 无状态的:每次请求之间相互独立,不能交互数据

历史版本

  • 1.0:每一次请求响应都会建立新的连接
  • 1.1:复用连接(创建连接,使用后  不会立即销毁,会判断后面的请求是否会用到此连接,如果用到则会复用)

请求消息数据格式

请求行

格式:请求方式 请求url 请求协议/版本

请求方式

  • get:请求参数在请求行中,在url后
  • post:请求参数在请求体中

请求头

格式:请求头:请求头值

 User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息

  • 可以解决浏览器兼容性问题

Referer:告诉服务器,当前请求从哪里来

  • 防盗链、统计工作(可以统计从baidu、新浪...来的用户)

请求空行

就是用于分割POST请求的请求头和请求体

请求体(正文)

封装post请求消息的请求参数

示例:浏览器是egde,使用post请求发送用户名和密码

 

 

分析:

 第一行为请求行,最后一行为请求体(请求的数据),剩余的全是请求头

响应消息数据格式

响应行

  • 组成:协议/版本 响应状态码 状态码描述

响应头

  • 格式:头名称:值

常见的响应头

  • Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
  • Content-disposition:服务器告诉客户端以什么格式打开响应体数据
    • in-line:默认值,在当前页面内打开
    • attachment;filename=xxx:以附件形式打开响应体。应用场景:文件下载

响应空行

响应体:传输的数据

  • 例如,发出的请求是一个页面,响应体就是页面信息

字符串格式

			//响应行
            HTTP/1.1 200 OK
            //响应头
			Content-Type: text/html;charset=UTF-8
			Content-Length: 101
            //响应空行
            
            //响应体
			<html>
			  <head>
			    <title>$Title$</title>
			  </head>
			  <body>
			  hello , response
			  </body>
			</html>

Request

request对象和response对象的原理

  • tomcat服务器会根据请求url中的资源路径,创建Servlet对象
  • tomcat服务器,会创建request、response对象,request对象中封装了请求数据
  • tomcat将request、response对象传递给service方法,并调用方法
  • 在service方法中,可以通过request获取请求消息数据,通过response设置响应消息数据
  • 服务器在给浏览器做出响应之前,会从response中取出设置的响应消息数据

request对象继承体系结构

        ServletRequest        --    接口
            |    继承
        HttpServletRequest    -- 接口
            |    实现
        org.apache.catalina.connector.RequestFacade (我们使用的形参 实际上是这个实现类对象)

获取请求消息

获取请求行的相关方法

  • String getMethod()   获取请求方式
  • String getContextPath()  获取虚拟目录
  • String getServletPath()  获取Servlet路径(资源路径,不包含虚拟目录)
  • String getQueryString()  获取get方式请求参数
  • String getRequestURI()    获取请求URI:虚拟目录/资源路径
  • StringBuffer getRequestURL()  获取请求URL:http://localhost/虚拟目录/资源路径
  • String getProtocol()   获取协议及版本
  • String getRemoteAddr()   获取客户机的IP地址
@WebServlet("/Servlet3")
public class Servlet3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //浏览器访问:http://localhost:8080/test/Servlet3?username=tony
        System.out.println(request.getMethod());//请求方式   GET
        System.out.println(request.getContextPath());//虚拟目录   /test
        System.out.println(request.getServletPath());//资源目录   /Servlet3
        System.out.println(request.getQueryString());//获取get方法请求参数   username=tony
        System.out.println(request.getRequestURI());//uri   /test/Servlet3
        System.out.println(request.getRequestURL());//url   http://localhost:8080/test/Servlet3
        System.out.println(request.getProtocol());//协议版本   HTTP/1.1
        System.out.println(request.getRemoteAddr());//客户机的ip地址   0:0:0:0:0:0:0:1
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

获取请求头的相关方法

  • String getHeader(String name)   通过请求头的名称获取请求头的值
  • Enumeration<String> getHeaderNames()   获取所有的请求头名称
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        System.out.println(request.getHeader("User-Agent"));//获取请求头数据   Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
        Enumeration<String> headerNames = request.getHeaderNames();//获取所有请求头名称  Enumeration枚举类型 遍历需要使用迭代器
        while (headerNames.hasMoreElements()){
            System.out.println(headerNames.nextElement());
        }
    }

获取请求体数据

步骤

  •  获取流对象
    • BufferedReader getReader():获取字符输入流,只能操作字符数据
    • ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据(场景:文件上传)
  • 再从流对象中拿数据
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        BufferedReader reader = request.getReader();
        String line;
        while ((line=reader.readLine())!=null){
            System.out.println(line);//username=admin&password=aaa
        }
        reader.close();
    }

获取请求的通用方法

  • String getParameter(String name)   根据参数名称获取参数值
  • String[] getParameterValues(String name)  根据参数名称获取参数值的数组  
  • Enumeration<String> getParameterNames():获取所有请求的参数名称
  • Map<String,String[]> getParameterMap():获取所有参数的map集合

中文乱码问题

  • request.setCharacterEncoding("utf-8");

请求转发

特点

  • 浏览器地址栏路径不发生变化
  • 只能转发到当前服务器内部资源中
  • 转发是一次请求

步骤

  • 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
  • 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response) 

共享数据

域对象:一个有作用范围的对象,可以在范围内共享数据

request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据(在转发中 共享的数据)

相关方法

  • void setAttribute(String name,Object obj):存储数据
  • Object getAttitude(String name):通过键获取值
  • void removeAttribute(String name):通过键移除键值对
@WebServlet("/Servlet2")
public class Servlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
       request.setAttribute("username","aaa");
       request.getRequestDispatcher("/Servlet4").forward(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
@WebServlet("/Servlet4")
public class Servlet4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(request.getAttribute("username"));
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

获取ServletContext

  • ServletContext getServletContext()

案例:用户登录

分析

//工具类
public class jdbc {
    private static DataSource dataSource;
    static {
        Properties properties = new Properties();
        try {
            properties.load(jdbc.class.getClassLoader().getResourceAsStream("druid.properties"));
            dataSource= DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static  DataSource getDataSource(){
        return  dataSource;
    }
}
//dao 定义登录方法
public class dao {
    private JdbcTemplate jdbcTemplate=new JdbcTemplate(jdbc.getDataSource());//多个操作共用一个JdbcTemplate
    public user login(user u){
        try {
            String sql="select * from user2 where username=? and password=?";
            user user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(user.class), u.getUsername(), u.getPassword());
            return user;
        }catch (DataAccessException e){
            e.printStackTrace();
            return null;//查询失败 返回null
        }
    }
}
//表单数据 将发送到servlet5
@WebServlet("/Servlet5")
public class Servlet5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        user user = new user();
        user.setUsername(username);
        user.setPassword(password);
        dao dao = new dao();
        user user1 = dao.login(user);
        if(user1==null){
            //登录失败 返回登录页面
            request.getRequestDispatcher("login.html").forward(request,response);
        }else{
            //将用户名放进request域中,并转发至成功页面
            request.setAttribute("name",username);
            request.getRequestDispatcher("/Servlet6").forward(request,response);
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
//成功登录 servlet6
@WebServlet("/Servlet6")
public class Servlet6 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
      String name = (String) request.getAttribute("name");

        response.getWriter().write(name+"登录成功");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

BeanUtils工具类,简化数据封装

用于封装JavaBean的(标准的Java类)

JavaBean的要求

  • 类必须被public修饰
  • 必须提供空参的构造器
  • 成员变量必须使用private修饰
  • 提供公共setter和getter方法

属性:setter和getter方法截取后的产物 

  • 例如:getUsername() --> Username--> username(一般属性和成员变量相同)

成员方法

  • setProperty()
  • getProperty()
  • populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中

示例代码 

//populate示例
        Map<String, String[]> map = request.getParameterMap();//获取所有的请求数据
        user user = new user();
        try {
            BeanUtils.populate(user,map);//将数据封装进user对象内
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
//setProperty、getProperty
        user user = new user();
        BeanUtils.setProperty(user,"username","tom");//给user对象的username属性设置为tom
        System.out.println(user);
        System.out.println(BeanUtils.getProperty(user,"username"));//获取user对象的username的值

Response

设置响应信息

设置响应行

  • 设置状态码:setStatus(int sc)

设置响应头

  • setHeader(String name, String value)

设置响应体

  • 获取输出流(getWriter()、getOutputStream()),使用输出流,将数据输出到客户端浏览器上

获取字节输出流需要设置字符集

  response.getOutputStream().write("你好".getBytes("utf-8"));

重定向(redirect)

 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
//        重定向的步骤
//        response.setStatus(302);//设置状态码为302
//        response.setHeader("location","/test/Servlet2");//设置响应头
//        简化形式
        response.sendRedirect("/test/Servlet2");
    }

原理

 特点

  • 地址栏发生变化
  • 重定向可以访问其他站点(服务器)的资源
  • 重定向是两次请求。不能使用request对象来共享数据

乱码问题

获取的流的默认编码是ISO-8859-1,需要设置该流的编码

response.setContentType("text/html;charset=utf-8");

补充知识

响应状态码

  • 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
  • 2xx:成功。代表:200
  • 3xx:重定向。代表:302(重定向),304(访问缓存)
  • 4xx:客户端错误。 404(请求路径没有对应的资源)  405:请求方式没有对应的doXxx方法
  • 5xx:服务器端错误。代表:500(服务器内部出现异常)

路径写法

  • 给客户端浏览器使用:需要加虚拟目录(重定向)
    • 建议虚拟目录动态获取:request.getContextPath()
  • 给服务器使用:不需要加虚拟目录(请求转发) 在服务器内部进行请求转发

案例:验证码

//绘制验证码
@WebServlet("/Servlet5")
public class Servlet5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        int width=100;
        int height=50;
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//图片对象
        Graphics graphics = bufferedImage.getGraphics();//获取画笔
        graphics.setColor(Color.PINK);//设置颜色
        graphics.fillRect(0,0,width,height);//绘制矩形
        graphics.setColor(Color.BLUE);
        graphics.drawRect(0,0,width-1,height-1);//绘制边框
        String str="QWERTYUIOPASDFGHJKLMNBVCXZ1234567890";
        Random random = new Random();
        for (int i = 0; i < 4; i++) {
            int i1 = random.nextInt(str.length());//获取随机值
            char c = str.charAt(i1);//获取元素
            graphics.drawString("    "+c+"",width/5*i,height/2);
        }
        //干扰线
        graphics.setColor(Color.GREEN);
        for (int i = 0; i < 5; i++) {
            int x1 = random.nextInt(width);
            int x2 = random.nextInt(width);
            int y1 = random.nextInt(height);
            int y2 = random.nextInt(height);
            graphics.drawLine(x1,y1,x2,y2);
        }
        ImageIO.write(bufferedImage,"jpg",response.getOutputStream());
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

//html页面
<body>
<img src="/test/Servlet5" id="img">
<br>
<a id="a_id" href="#">看不清,换一张</a>
<script>
    let img = document.getElementById("img");
    let a_id = document.getElementById("a_id");
    img.onclick=function () {
        img.src="/test/Servlet5?data"+new Date().getTime();
    }
    a_id.onclick=function () {
        img.src="/test/Servlet5?data"+new Date().getTime();
    }
</script>
</body>

ServletContext对象

获取方法

  • 通过request对象获取 request.getServletContext();
  • 通过HttpServlet获取  this.getServletContext();
  • 两个方法获取的是同一个对象

其它方法

获取MIME类型 String getMimeType(String filename)  

  • MIME类型:在互联网通信过程中定义的一种文件数据类型    格式: 大类型/小类型   text/html

域对象:共享数据

  • setAttribute(String name,Object value)
  • getAttribute(String name)
  • removeAttribute(String name)
  • 范围:所有用户所有请求的数据

获取文件的真实路径:方法:String getRealPath(String path) 

 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        ServletContext servletContext = this.getServletContext();
        System.out.println(servletContext.getRealPath("/c.txt"));//获取web目录下的文件路径
        System.out.println(servletContext.getRealPath("/WEB-INF/b.txt"));//WEB-INF目录下的文件路径
        System.out.println(servletContext.getRealPath("/WEB-INF/classes/a.txt"));//src目录下的文件路径
    }

案例:文件下载

@WebServlet("/Servlet7")
public class Servlet7 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String filename = request.getParameter("filename");//获取文件名
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("/WEB-INF/img/" + filename);
        FileInputStream fileInputStream = new FileInputStream(realPath);//读取文件
        String mimeType = servletContext.getMimeType(filename);//获取文件mime类型
        response.setHeader("content-type",mimeType);//设置响应头类型 服务器告诉客户端的文件类型

        String agant = request.getHeader("user-agent");//解决中文名称问题,目的就是让弹窗显示中文名
        filename=DownLoadUtils.getFileName(agant,filename);//DownLoadUtils是一个工具类 传入客户端的浏览器信息和文件名

        response.setHeader("content-disposition","attachment;filename="+filename);//打开方式为副本 固定格式
        ServletOutputStream outputStream = response.getOutputStream();//将读取到的文件信息写入到服务器内存
        byte[]bytes=new byte[1024*8];
        int len=0;
        while ((len=fileInputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
<body>
<a href="/test/Servlet7?filename=2.jpg">图片1</a>
<a href="/test/Servlet7?filename=九尾.jpg">图片2</a>
<a href="/test/Servlet7?filename=1.avi"> 视频1</a>
</body>

这篇关于JavaWeb技术:Tomcat、servlet的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!