tomcat和servlet快速入门教程!!!

2021-11-15 11:40:44 浏览数 (1)

Tomact和servlet快速入门教程

  • tomcat的入门必备知识
    • 1.下载:
    • 2.安装: 解压压缩包即可
    • 3.卸载: 删除目录即可
    • 4.启动:
    • 5.关闭:
    • 6.部署:
      • 静态项目和动态项目
  • 将tomcat集成到IDEA中,并且创建JavaEE项目,部署项目
  • Servlet
    • web动态工程目录介绍
    • 热部署
    • 快速入门
    • URL地址定位实现原理
    • 生命周期方法
  • 注解配置
    • 步骤:
  • IDEA与tomcat的相关配置
  • Servlet的体系结构
  • Servlet的urlpattern配置
  • Http
    • Http请求数据格式
  • Request对象
    • Request对象的继承体系结构
    • Request的功能
      • 获取请求行数据
      • 获取请求头数据
      • 获取请求体数据
      • 获取请求参数的通用方式
        • 根据参数名获取参数值:
        • 根据参数名称获取参数值数组,多用于复选框:
        • 获取所有请求的参数名称
        • 获取所有参数的map集合
        • 请求中的中文乱码问题
    • 请求转发
      • 步骤
    • 共享数据(域对象)
    • 获取ServletContext对象
    • 用户登录案例
      • 案例需求
      • 案例分析
      • 环境准备
        • login.html中的form表单的action路径写法
    • BeanUtils工具类,简化数据封装
      • JavaBean: 标准的Java类
      • 概念
      • 方法
  • HTTP响应消息
    • 1. 响应行
    • 2. 响应头
    • 3. 响应空行
    • 4. 响应体: 传输的数据
  • Reponse对象
    • 1.设置响应行
    • 2.设置响应头
    • 3.设置响应体
  • 案例之完成重定向
    • 简单的重定向写法:
  • 重定向和转发的区别和各自特点
  • 路径写法
    • 路径分类
    • 动态获取虚拟目录
    • 服务器输出字符数据到浏览器
      • 中文乱码问题
    • 服务器输出字节数据到浏览器
    • 字节输出流案例----验证码
  • ServletContext对象
    • 获取
    • 功能
    • 1.获取MIME类型
    • 2.域对象,共享数据
    • 3.获取文件服务器路径
    • 文件下载案例
      • 中文文件名问题

tomcat的入门必备知识

1.下载:

tomcat官网下载地址

2.安装: 解压压缩包即可

注意:安装目录建议不要有中文和空格

3.卸载: 删除目录即可

4.启动:

4.1 bin/startup.bat ,双击运行该文件即可 4.2 访问:浏览器输入: http://localhost:8080 回车访问自己 或者 http://别人的ip:8080 访问别人 可以通过ipconfig:查看本机ip地址

4.3 启动可能出现的问题:

4.3.1 黑窗口一闪而过:

原因: 没有正确配置JAVA_HOME环境变量

4.3.2 启动报错:

原因: 端口号被占用

推荐的解决方法1: 找到占用的端口号,并且找到对应的进行,杀死该进程

在cmd窗口输入netstat -ano

打开任务管理器,找到刚才的进程ID,然后结束该进程

解决方法2: 修改自身端口号

conf/server.xml用记事本打开,将其默认端口号修改即可,可能还需要连带着修改其他的相关默认端口号才行

一般会把tomcat的默认端口号修改为80. 80端口号是http协议的默认端口号 好处:在访问时,就不需要输入端口号了

5.关闭:

强制关闭: 点击窗口的x 正常关闭: bin/shutdown.bat 或者ctrl c

6.部署:

部署方式: 1.直接将项目放到webapps目录下即可 /hello: 项目的访问路径---->虚拟目录 简化部署:将项目打包成一个war包,再将war包部署到webapps目录下面 war包会自动解压缩.

2.配置conf/server.xml文件 在< Host >标签体中配置

代码语言:javascript复制
<Context docBase="D:hello" path="/hehe" />

docBase: 项目存放的路径 path: 虚拟目录

3.在confCatalinalocalhost创建了一个任意名称的xml文件。 在文件中编写:

代码语言:javascript复制
<Context docBase="D:hello"/>

虚拟目录就是xml文件的名称

静态项目和动态项目

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


将tomcat集成到IDEA中,并且创建JavaEE项目,部署项目

tomcat集成到IDEA的教程


Servlet

概念:运行在服务器端的小程序 Servlet就是一个接口,定义了Java类被浏览器访问到的(tomcat)规则 将来我们自定义一个类,实现Servlet接口,复写方法

web动态工程目录介绍


热部署

Tomcat上的部署问题,有时候也是个麻烦的问题,要是不采用热部署,我们就只能每次对原来的文件做一次改动的时候就要重新部署,而每次重新部署都要关闭tomcat,部署完重启tomcat,可见这是一个多么烦人的事情。现在,我们可以采用热部署了,以后,就不用做烦人的关闭重起工作。

热部署的设置:


快速入门

  1. 创建JavaEE项目
  2. 定义一个类,实现Servlet的接口
  3. 实现接口中的抽象方法
  4. 配置servler

在wed.xml的< web-app >标签里面进行配置:

代码语言:javascript复制
<?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标签Servlet程序起一个别名(一般是类名)-->
        <servlet-name>demo1</servlet-name>
        <!--servlet-class是servlet的全类名-->
        <servlet-class>web.servlet.servletDemo</servlet-class>
    </servlet>
    <!--给servlet程序配置访问地址-->
    <servlet-mapping>
        <!--告诉服务器,我当前配置的地址给哪个servlet程序使用-->
        <servlet-name>demo1</servlet-name>
        <!--配置访问地址
           / 斜杠在服务器解析的时候表示地址为: http://ip:port/工程路径
           /demo1 表示地址为:  http://ip:port/工程路径/demo1
        -->
        <url-pattern>/demo1</url-pattern>
    </servlet-mapping>
</web-app>

常见错误: url-pattern配置的路径中没有以斜杠打头 servlet-name配置的值不存在 servlet-class标签全类名配置错误

工程路径名修改:


URL地址定位实现原理

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


生命周期方法

servlet中的生命周期:

  1. 被创建: 执行Init方法,只执行一次
  2. 提供服务: 执行service方法,执行多次
  3. 被销毁: 执行destory方法,只执行一次

Servlet的创建时机: 默认情况下,第一次被访问时,Servlet被创建 可以配置执行Sevlet的创建时机,如下:

代码语言:javascript复制
<?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标签Servlet程序起一个别名(一般是类名)-->
        <servlet-name>demo1</servlet-name>
        <!--servlet-class是servlet的全类名-->
        <servlet-class>web.servlet.servletDemo</servlet-class>

      <!--  指定Servlet的创建时机
           1.第一次被访问时,创建
            <load-on-startup>的值为负数
            2.在服务器启动时,创建
             <load-on-startup>的值为0或者正整数
      -->
        <load-on-startup>5</load-on-startup>
    </servlet>
    <!--给servlet程序配置访问地址-->
    <servlet-mapping>
        <!--告诉服务器,我当前配置的地址给哪个servlet程序使用-->
        <servlet-name>demo1</servlet-name>
        <!--配置访问地址
           / 斜杠在服务器解析的时候表示地址为: http://ip:port/工程路径
           /demo1 表示地址为:  http://ip:port/工程路径/hello
        -->
        <url-pattern>/demo1</url-pattern>
    </servlet-mapping>
</web-app>

Servlet的init方法只执行一次,说明Servlet在内存中只存在一个对象,说明Servlet是单例的

  1. 多个对象同时访问时,可能存在线程安全问题
  2. 解决: 净量不要再Servlet中定义成员变量.即使定义了成员变量也不要修改其值

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

Servlet被销毁时执行。服务器关闭时,Servlet被销毁。 只有服务器正常关闭时,才会执行destory 销毁方法在对象被销毁前执行


注解配置

Servlet 3.0以上才支持注解配置,支持注解配置后,就不需要web.xml了。

对于web.xml来说,对应的每一个servlet工程都需要重新配置一个web.xml太过繁琐

步骤:

  1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
  2. 定义一个类来实现Servlet的接口
  3. 复写方法
  4. 在类上使用@WebServlet注解,进行配置

注解就是加在类上面的,因此不需要关心全类名了,也就不需要再通过name属性做对应关系了

代码语言:javascript复制
@WebServlet(urlPatterns="资源路径");
简化写法---->注解中最重要的属性value,其实就是urlPatterns属性,因此可以省略value
@WebServlet("资源路径");

IDEA与tomcat的相关配置


Servlet的体系结构


Servlet的urlpattern配置

1. urlpattern:servlet的访问路径

2.一个servlet可以定义多个访问路径: @WebServlet({"/Demo2","/dhy","/ly"})

3.路径定义规则:

1. /xxx 2. /xxx/xxx :多层路径,目录结构

  1. *.xxx

Servlet的url详解


Http


Http请求数据格式


Request对象


Request对象的继承体系结构


Request的功能

获取请求行数据

代码演示:

代码语言:javascript复制
package request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/RequestServlet")
public class RequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  //1.获取请求方式: GET
        String method=request.getMethod();
        System.out.println(method);
        //2.获取虚拟目录: /demo2
        String contextPath=request.getContextPath();
        System.out.println(contextPath);
        //3.获取servlet路径:/RequestServlet
        String servletPath=request.getServletPath();
        System.out.println(servletPath);
        //4.获取get方式请求参数: name=dhy
        String queryString=request.getQueryString();
        System.out.println(queryString);
        //5.获取请求URI: /demo2/RequestServlet
        String requestURI=request.getRequestURI();
        StringBuffer requestURL=request.getRequestURL();
        System.out.println(requestURI);
        System.out.println(requestURL);
        //6.获取协议及版本: HTTP/1.1
        String  protocol=request.getProtocol();
        System.out.println(protocol);
        //7.获取客户机的IP地址
        String remoteAddr=request.getRemoteAddr();
        System.out.println(remoteAddr);
        
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

获取请求头数据

获取所有头名称代码演示:

代码语言:javascript复制
package request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/req")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求头数据
        //1.获取所有请求头名称
        Enumeration<String> headerNames=request.getHeaderNames();
        //2.遍历
        while(headerNames.hasMoreElements())
        {
            String name=headerNames.nextElement();
            //更据名称获取请求头的值
            String header=request.getHeader(name);
            System.out.println(name "------" header);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

获取浏览器版本相关信息代码演示:

代码语言:javascript复制
package request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/req")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           //演示获取请求头数据: user-agent
        String agent=request.getHeader("user-agent");//不区分大小写

        //判断agent的浏览器版本:
        if(agent.contains("Chrome"))
        {
            System.out.println("当前正在使用的是谷歌浏览器");
        }
        else if(agent.contains("Firefox"))
        {
            System.out.println("当前正在使用火狐浏览器");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

告诉服务器请求从哪里来—referer:

代码语言:javascript复制
package request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/req")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           //演示获取请求头数据: user-agent
        //告诉服务器请求当前servlet实例的请求从哪里来的,是否来自指定网址
        String referer=request.getHeader("referer");//不区分大小写
        System.out.println(referer); //  http://localhost:8080/demo2/login.html

      //防止盗链
        if(referer!=null)
        {
            if(referer.contains("/demo2"))
            {
                System.out.println("下面播放极限挑战");
            }
            else//盗链
                System.out.println("请付费支持正版");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

获取请求体数据

代码演示:

代码语言:javascript复制
package request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求消息体----请求参数

        //1.获取请求字符流
        BufferedReader br=request.getReader();
        //2.读取数据
        String line=null;
        while((line=br.readLine())!=null)
        {
            System.out.println(line);
        }

    }
}

login.html

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<form action="/demo2/demo" method="post">//action属性:设置表单提交的服务器地址
    <input type="text" placeholder="请输入用户名" name="username"><br>
    <input type="text" placeholder="请输入密码" name="password"><br>
    <input type="submit" value="注册"><br>

</form>
</body>
</html>

获取请求参数的通用方式

根据参数名获取参数值:
代码语言:javascript复制
package request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        //获取get请求参数
        //根据参数名称获取参数值
        String username=request.getParameter("username");
        System.out.println("get方式:");
        System.out.println(username);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
      //获取post请求参数
     //根据参数名称获取参数值
/*        String username=request.getParameter("username");
        System.out.println("post方式:");
        System.out.println(username);*/
        //因为doPost方法里面的代码逻辑和doGet方法里面代码逻辑相同,因此可以在doPost方法里面直接调用doGet方法
        //简化代码书写
        doGet(request,response);
    }
}
根据参数名称获取参数值数组,多用于复选框:
代码语言:javascript复制
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        String[] hobbies=request.getParameterValues("hobby");
        for(String hobby:hobbies)
            System.out.println(hobby);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doGet(request,response);
    }
}
获取所有请求的参数名称
代码语言:javascript复制
     Enumeration<String> names= request.getParameterNames();
            while(names.hasMoreElements())
            {
                String name=names.nextElement();
                String value=request.getParameter(name);
                System.out.println(name ":" value);//对于复选框,如果有多个参数值,那么这里只能获取第一个参数值,除非用数组形式获取
            }
获取所有参数的map集合
代码语言:javascript复制
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> strings = parameterMap.keySet();
        for(String value:strings)
        {
            //根据key获取值
            String[] strings1 = parameterMap.get(value);
            for(String s:strings1) {
                System.out.println("key="   value   "  value="   s);
            }
        }

上面的四种方法,第一种和第四种较为常用


请求中的中文乱码问题
  1. tomcat 8已经将get方式乱码解决,如果get方式还是有乱码,去配置中修改
  1. post方式中文会乱码

解决: 获取参数前,设置request的编码:

代码语言:javascript复制
 //1.设置流的编码
        request.setCharacterEncoding("utf-8");

代码:

代码语言:javascript复制
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        //1.设置流的编码
        request.setCharacterEncoding("utf-8");

        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> strings = parameterMap.keySet();
        for(String value:strings)
        {
            //根据key获取值
            String[] strings1 = parameterMap.get(value);
            for(String s:strings1) {
                System.out.println("key="   value   "  value="   s);
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doGet(request,response);
    }

请求转发

一种在服务器内部资源跳转的方式

步骤

代码:

代码语言:javascript复制
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        System.out.println("转发到dem0....");
        //转发到reqServlet3下面的资源
/*        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/reqServlet3");
requestDispatcher.forward(request,response);*/
        //一般多为链式编程
        request.getRequestDispatcher("/reqServlet3").forward(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doGet(request,response);
    }
}
代码语言:javascript复制
@WebServlet("/reqServlet3")
public class reqServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("转发到reqServlet3....");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

共享数据(域对象)

域对象: 一个有作用范围的对象,可以在范围内共享数据 request 域: 代表一次请求的范围,一般用于请求转发的多个资源中共享数据

方法:

一般只有转发的情况下,才可以用request域共享数据

代码演示:

代码语言:javascript复制
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        System.out.println("转发到dem0....");
        //存储数据到request域中
        request.setAttribute("name","大忽悠");

        request.getRequestDispatcher("/reqServlet3").forward(request,response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doGet(request,response);
    }
}
代码语言:javascript复制
@WebServlet("/reqServlet3")
public class reqServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object name = request.getAttribute("name");
        System.out.println((String)name);
        System.out.println("转发到reqServlet3....");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

获取ServletContext对象

代码语言:javascript复制
 ServletContext servletContext = request.getServletContext();

用户登录案例

案例需求

案例分析

环境准备

  1. 创建项目,导入html页面,配置文件,导入jar包
  2. 创建数据库环境
代码语言:javascript复制
USE test1;
CREATE TABLE USER(
  id INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(20) UNIQUE NOT NULL,
  PASSWORD VARCHAR(32) NOT NULL
);

3.创建一个user类

代码语言:javascript复制
package domain;

public class user {
    private int id;
    private  String username;
    private  String password;

    public user(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public user() {
    }

    public int getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

4.创建操作数据库中user表的类—UserDao

代码语言:javascript复制
package Dao;

import Utils.JDBCUtils;
import domain.user;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

public class userDao {
    //声明JDBCTemplate对象共用
    private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
    //登录方法
    public user login(user loginUser)
    {
        try
        {
            //编写sql语句
            String sql="select * from user where username= ? and password= ?";
            //调用query方法---返回一个查到的user对象
            user user = template.queryForObject(sql, new BeanPropertyRowMapper<user>(user.class), loginUser.getUsername(), loginUser.getPassword());
            //loginUser: 只包含用户名和密码
            //返回的user: 包括用户全部数据
            return user;
        }
        catch (DataAccessException e)
        {
            e.printStackTrace();
            //没有查询到,返回null
            return null;
        }
    }

}

一个例子教你看源码!深入浅出教你理解Template中的query和queryForObject的区别!

5.工具类

代码语言:javascript复制
package Utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class JDBCUtils {
    //定义成员变量---连接池对象
    private static DataSource ds;
    static {
        try {
            //加载配置文件
            Properties pro=new Properties();
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            //初始化连接池对象
            ds= DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    //获取连接池对象
      public static  DataSource getDataSource()
      {
          return ds;
      }
    //获取连接Connection对象
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

}
  1. loginServlet类完成登录的具体逻辑
代码语言:javascript复制
在这里插入代码片

7.login.html

login.html中的form表单的action路径写法

虚拟目录 Servlet的资源路径

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<form action="/demo5/LoginServlet" method="post">
    用户名: <input type="text" name="username" placeholder="请输入用户名"><br>
    密码: <input type="password" placeholder="请输入密码" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

8.配置文件

代码语言:javascript复制
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test1
username=root
password=root
#初始化连接数量
initialSize=5
#最大连接数
maxActive=10
#最大等待时间
maxWait=3000

最新版的IDEA需要把配置文件放置到如下两个地方:

否则报如下错误:

9.loginServlet–负责登录的相关逻辑

代码语言:javascript复制
import Dao.userDao;
import domain.user;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        request.setCharacterEncoding("utf-8");
        //2.获取请求参数
        String usermame= request.getParameter("username");
        String password = request.getParameter("password");
        //3.封装user对象
        user loginUser=new user(usermame,password);
        //4.调用userDao的login方法
        userDao dao=new userDao();
        user user=dao.login(loginUser);
        //5.判断user
        if(user==null)
            //登录失败
       request.getRequestDispatcher("/FailServlet").forward(request,response);
        else
        {
            //登录成功
            //存储数据
            request.setAttribute("user",user);//将查到的user对象存入
            //转发
            request.getRequestDispatcher("/SuccessServlet").forward(request,response);
        }


    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

10.FailServlet—处理登录失败的逻辑

代码语言:javascript复制
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/FailServlet")
public class FailServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//给页面写一句话
        //设置页面的编码
        response.setContentType("text/html;charset=utf-8");
        System.out.println("登录失败");
        //输出
        response.getWriter().write("登录失败,用户名或者密码错误");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     doGet(request,response);
    }
}

11.SuccessServlet—处理登录成功的逻辑

代码语言:javascript复制
import domain.user;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet("/SuccessServlet")
public class SuccessServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         //获取request域中共享的user对象
       user user= (user)request.getAttribute("user");
       //给页面写一句话

        //设置编码
        response.setContentType("text/html;charset=utf-8");
        System.out.println("登录成功");
        //输出
        response.getWriter().write("欢迎" user.getUsername() "用户");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
    }
}

效果演示:

数据库目前只有一位用户登录成功:

登录失败的演示:

登录成功的演示:


BeanUtils工具类,简化数据封装

用于封装JavaBean的

JavaBean: 标准的Java类

  1. 类必须被public修饰
  2. 必须提供空参的构造器
  3. 成员变量必须使用private修饰
  4. 必须提供公共的setter和getter方法
  5. 一般像这种JavaBean的类都会放在domain等的包下面

功能:封装数据

概念

  1. 成员变量
  2. 属性: setter和getter截取后的产物,例如: getUsername()—>Username(下一步变小写)–>username,这里的username一般就是成员变量的名字 这里是通过通过传入的字符串和方法名截取后的产物进行比对,找到正确的方法,来设置属性值或者得到属性值

方法

  1. setProperty()—>给属性赋值
  2. getProperty()---->得到属性的值
  3. populate(Object obj,Map map):将map集合的键值对信息封装到对应的JavaBean对象中,把键作为属性的名称,值作为JavaBean对应属性的值

BeanUtils工具类使用前要导入jar包

setProperty()和getProperty()方法演示:

代码语言:javascript复制
     user loginUser=new user();
        //设置loginUser的属性
        BeanUtils.setProperty(loginUser,"username","大忽悠");
        System.out.println(loginUser);
代码语言:javascript复制
    user loginUser=new user("大忽悠","123456");
        String name= BeanUtils.getProperty(loginUser,"username");
        System.out.println(name);

populate方法演示:

代码语言:javascript复制
/*

        //2.获取请求参数
        String usermame= request.getParameter("username");
        String password = request.getParameter("password");
        //3.封装user对象
        user loginUser=new user(usermame,password);
*/

        //获取所有请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        //创建user对象
        user loginUser=new user();
        //使用BeanUtils进行封装
        try {
            BeanUtils.populate(loginUser,parameterMap);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

HTTP响应消息

服务器端发送给客户端的数据

数据格式:

1. 响应行

2. 响应头

3. 响应空行

4. 响应体: 传输的数据


Reponse对象

设置响应消息

1.设置响应行

  1. 格式: http/1.1 200 ok
  2. 设置状态码: setStatus(int sc)

2.设置响应头

代码语言:javascript复制
setHeader(String name,String value);

3.设置响应体

使用步骤:

  1. 获取输出流
  1. 使用输出流,将数据输出到客户端浏览器

案例之完成重定向

重定向: 资源跳转的方式

代码演示:

代码语言:javascript复制
        //访问Demo1资源,自动跳转到Demo2资源
        //1.设置状态码为302
        response.setStatus(302);
        //2.设置响应头location
        response.setHeader("location","/Demo2Servlet");

简单的重定向写法:

代码语言:javascript复制
 response.sendRedirect("/Demo2Servlet");

重定向和转发的区别和各自特点


路径写法

路径分类

不写默认代表./ ,即当前目录下

动态获取虚拟目录

代码语言:javascript复制
        String contextPath = request.getContextPath();//虚拟目录
        response.sendRedirect(contextPath "/Demo2Servlet");

服务器输出字符数据到浏览器

  1. 获取字符输出流
  2. 输出数据

代码演示:

代码语言:javascript复制
        //获取字符输出流
        PrintWriter writer = response.getWriter();
        //输出数据
        writer.write("<font color=red size=5>Hello world</font>");

中文乱码问题

解决方法:

代码语言:javascript复制
        //获取流对象之前,设置流的默认编码: ISO-8859-1 设置为GBK
        response.setCharacterEncoding("GBK");
        //获取字符输出流
        PrintWriter writer = response.getWriter();
        //输出数据
        writer.write("<font color=red size=5>大忽悠</font>");

如果在不知道浏览器编码格式的情况下,解决方法如下:

代码语言:javascript复制
      //获取流对象之前,设置流的默认编码: ISO-8859-1 设置为GBK
        response.setCharacterEncoding("utf-8");
        //告诉浏览器,服务器发送的消息体数据编码,建议浏览器使用该编码编码
        response.setHeader("content-type","text/html;charset=utf-8");
        //获取字符输出流
        PrintWriter writer = response.getWriter();
        //输出数据----这里可以使用html标签,浏览器可以解析
        writer.write("<font color=red size=5>大忽悠</font>");

对上面一种方法的简化写法:

代码语言:javascript复制
          response.setContentType("text/html;charset=utf-8");
        //获取字符输出流
        PrintWriter writer = response.getWriter();
        //输出数据
        writer.write("<font color=red size=5>大忽悠来了</font>");

服务器输出字节数据到浏览器

  1. 获取字节输出流
  2. 输出数据

代码演示:

代码语言:javascript复制
        response.setContentType("text/html;charset=utf-8");
        //获取字节输出流
        ServletOutputStream outputStream = response.getOutputStream();
        //输出数据
        outputStream.write("大忽悠".getBytes(StandardCharsets.UTF_8));//如果这里不设置字符集,默认使用GBK

一般使用字节输出流来输出图片和视频,而非文本信息


字节输出流案例----验证码

验证码本质是个图片,目的是为了来防止恶意表单注册

完整代码演示:

Demo1Servlet:

代码语言:javascript复制
package com.example.DEMO7;

import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Random;

@WebServlet("/Demo1Servlet")
public class Demo1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int width=150;
        int height=50;
        //1.在内存中创建一个图片----创建一个不带透明色的对象
        BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

        //2.填充背景色
        Graphics g=image.getGraphics();//画笔对象
        g.setColor(Color.PINK);
         g.fillRect(0,0,width,height);
        //3.画边框
        g.setColor(Color.BLUE);
        g.drawRect(0,0,width-1,height-1);

        //4.随机生成验证码
        String str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random ran=new Random();
        for(int i=1;i<=4;i  )
        {
          //生成随机角标
            int index=ran.nextInt(str.length());
            //获取字符
            char ch=str.charAt(index);
            //写验证码
            g.drawString(ch " ",width/5*i,height/2);
        }
        //7.画干扰线
        //随机生成坐标点
        for(int i=0;i<4;i  )
        {
            int x1=ran.nextInt(width);
            int x2=ran.nextInt(width);
            int y1=ran.nextInt(height);
            int y2=ran.nextInt(height);
            g.setColor(Color.RED);
            g.drawLine(x1,y1,x2,y2);
        }
        //8.将图片输出到页面上----第二个参数是后缀名,第三个参数是一个输出流
        ImageIO.write(image,"jpg",response.getOutputStream());
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

register.html

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>战地六中国区官网</title>
    <script>
        /*
        * 分析:
        * 点击超链接或者图片,需要换一张验证码图片
        * 1.给超链接和图片绑定单击事件
        * 2.重新设置图片的src属性值
        * */
        //当页面加载完成,触发下面的事件
        window.onload=function (){
            //1.获取图片对象
            var img=document.getElementById("checkCode");
            //2.绑定单击事件
            img.onclick=function ()
            {
                //浏览器会有缓存,因此需要加一个时间戳,保证每次的资源路径都不同
                var date=new Date().getTime();
                img.src="/Demo7/Demo1Servlet?" date;
            }
        }
    </script>
</head>
<body>
<form  action="/Deom7/Demo1Servlet" method="get">
    游戏激活码:<input type="text" placeholder="请输入激活码"><br>
    验证码:<input type="text" placeholder="输入图片验证码">&nbsp;&nbsp;&nbsp;
    <img id="checkCode" src="/Demo7/Demo1Servlet"/>
    <a id="change" href="http://localhost/Demo7/register.html">看不清换一张?</a>
</form>
</body>
</html>

ServletContext对象

概念: 代表整个web应用,可以和程序的容器来通信

获取

代码演示:

代码语言:javascript复制
           //1.通过request对象获取
        ServletContext servletContext = request.getServletContext();
        //2.通过HttpServlet获取
        ServletContext servletContext1 = this.getServletContext();
        System.out.println(servletContext1);
        System.out.println(servletContext);
        System.out.println(servletContext1==servletContext);//true

功能

1.获取MIME类型

代码演示:

代码语言:javascript复制
     //通过HttpServlet获取
        ServletContext servletContext = getServletContext();
        //定义文件名称
        String filename="a.jpg";
        //获取MIME类型
        String mimeType = servletContext.getMimeType(filename);
        System.out.println(mimeType);

2.域对象,共享数据

ServletContext对象的生命周期从服务器被创建时开始,到服务器被关闭时结束,并且作用范围很广,为所有用户,因此要谨慎使用

3.获取文件服务器路径

服务器中不同目录下的文件获取时填写路径不同,需要注意

代码语言:javascript复制
            //获取ServletContext对象----HTTP方式
        ServletContext servletContext = getServletContext();

        //获取文件的服务器路径
        //web目录下的资源访问
        String realPath = servletContext.getRealPath("/b.txt");
        System.out.println(realPath);

        //web-inf目录下的资源访问
        String realPath1 = servletContext.getRealPath("/WEB-INF/c.txt");
        System.out.println(realPath1);

        //java目录下的资源访问
        String realPath2 = servletContext.getRealPath("/WEB-INF/classes/a.txt");
        System.out.println(realPath2);

文件下载案例

文件下载需求:

  1. 页面显示超链接
  2. 点击超链接后弹出下载提示框
  3. 完成图片文件下载

分析:

步骤:

上面说过的响应头相关知识回顾:

代码实现:

代码语言:javascript复制
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求参数,即文件名称
        String filename=request.getParameter("filename");
        //使用字节输入流加载文件进内存
        //第一步: 找到文件服务器路径
        ServletContext servletContext = getServletContext();
        String realPath = servletContext.getRealPath("/img/"   filename);
        //第二步: 用字节流关联
        FileInputStream fis=new FileInputStream(realPath);

        //设置response的响应头
        //第一步: 设置响应头的类型: content-type
        String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
        response.setHeader("content-type",mimeType);
        //第二步: 设置响应头打开的方式: content-disposition
        response.setHeader("content-disposition","attachment;filename=" filename);//filename=....弹出提示框的名字

        //将输入流数据写到输出流中
        ServletOutputStream outputStream = response.getOutputStream();
           byte[] buff=new byte[1024*8];
           int len=0;
           while((len=fis.read(buff))!=-1)
           {
               outputStream.write(buff,0,len);
           }
           //关闭输入流
        fis.close();
    }

downLoad.html:

代码语言:javascript复制
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<a href="/demo9/img/cat.png">可爱小猫</a>
<a href="/demo9/img/lion.png">猛狮</a>
<hr>
<font color="#ff69b4" size="5">下面链接,点击下载图片</font><br>
<a href="/demo9/downLoadServlet?filename=cat.png">小猫图片下载</a>
<a href="/demo9/downLoadServlet?filename=lion.png">狮子图片下载</a>
</body>
</html>

中文文件名问题

解决:

如果jdk版本打印1.8,那么需要手动导入BASE64Encoder的jar包,方可使用其工具类

工具类代码:

代码语言:javascript复制
package com.example.Demo9;
import Decoder.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class downLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace(" ", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?"   base64Encoder.encode(filename.getBytes("utf-8"))   "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

之前出问题的servlet主类:

代码语言:javascript复制
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求参数,即文件名称
        String filename=request.getParameter("filename");
        //使用字节输入流加载文件进内存
        //第一步: 找到文件服务器路径
        ServletContext servletContext = getServletContext();
        String realPath = servletContext.getRealPath("/img/"   filename);
        //第二步: 用字节流关联
        FileInputStream fis=new FileInputStream(realPath);

        //设置response的响应头
        //第一步: 设置响应头的类型: content-type
        String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
        response.setHeader("content-type",mimeType);
        //第二步: 设置响应头打开的方式: content-disposition
        
        ///
        //解决中文文件名问题
        //1.获取user-agent请求头
        String agent=request.getHeader("user-agent");
        //2.使用工具类方法编码文件名即可
        filename = downLoadUtils.getFileName(agent, filename);
        ///
        
        response.setHeader("content-disposition","attachment;filename=" filename);//filename=....弹出提示框的名字

        //将输入流数据写到输出流中
        ServletOutputStream outputStream = response.getOutputStream();
           byte[] buff=new byte[1024*8];
           int len=0;
           while((len=fis.read(buff))!=-1)
           {
               outputStream.write(buff,0,len);
           }
           //关闭输入流
        fis.close();
    }

0 人点赞