A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 慢慢慢时光 初级黑马   /  2019-3-28 13:40  /  919 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

学习目标1. Tomcat & Servlet
  • 能够理解WEB动态资源概念
  • 能够安装、启动和关闭Tomcat服务器
  • 掌握运用Tomcat服务器部署WEB项目的三种方式
  • 能够说出Servlet的编写流程
  • 能够说出Servlet的生命周期
  • 能够使用注解开发Servlet
  • 能够理解HTTP协议请求内容的格式
  • 能够处理HTTP请求参数的乱码问题
  • 能够使用Request对象获取HTTP协议请求头的值

2. cookie& session
  • 能够说出会话的概念
  • 能够说出两种会话技术的区别
  • 能够创建、发送、接收、删除cookie
  • 能够说出cookie执行的原理
  • 能够获取session对象、添加、删除、获取session
  • 能够说出session执行的原理
  • 能够说出session的创建、销毁机制

3. EL && JSTL
  • 能够说出el表达式的作用
  • 能够使用el表达式获取javabean的属性
  • 能够使用jstl标签库的if标签
  • 能够使用jstl标签库的foreach标签

5. filter & listener
  • 能够说出过滤器的作用
  • 能够编写过滤器
  • 能够说出过滤器声明周期相关方法
  • 能够根据过滤路径判断指定的过滤器是否起作用
  • 能够理解什么是过滤器链
  • 能够完成filter完成用户登录验证案例
  • 能够理解动态代理对类的方法进行增强
  • 能够了解listener概念

day13 Tomcat&Servlet1. web服务器软件1. 服务器
安装了服务器软件的计算机
2. 服务器软件
接收用户的请求,处理请求,做出响应
web服务器软件:接收用户的请求,处理请求,做出响应
  • 在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
  • web容器

3. 常见java相关的web软件
  • webLogic: oracle公司,大型的JavaEE服务器,支持所有的JavaEE规范,收费
  • webSphere: IBM
  • JBOSS:  JBOSS公司
  • Tomcat: Apache基金组织,中小型,支持少量javaEE规范servlet/jsp,开源的,免费的

4. javaEE:
java语言在企业级开发中使用的技术规范的综合,一共规定了13项大的规范。
2. Tomcat1. 安装卸载相关
  • 下载
  • 安装
  • 卸载
  • 启动
    • bin/startup.bat,双击运行该文件即可
    • 访问:浏览器输入:http://localhost:8080   http:别人的ip:8080

  • 关闭
    • 正常关闭 ctrl+c  或者打开shutdown.bat
    • 暴力关闭 直接点close

  • 配置

启动可能遇到的问题:
  • 黑窗口一闪而过:
    • 原因:没有正确配置JAVA_HOME环境变量,或者CATALINA_HOME之类的环境变量错误
    • 解决方案:正确配置JAVA_HOME环境变量,或者在CMD命令行启动,会报相应的错
    • 或者编辑 startup.bat,在末尾加一个pause

  • 启动报错
    • 暴力:找到占用的端口号,并且找到对应的进程,杀死该进程
      • netstat -ano

    • 温柔:修改自己的端口号
      • conf/server.xml
      • <Connector port="8888" protocol="HTTP/1.1"
      • 一般会将tomcat的默认端口号修改为80。80端口号是http协议的默认端口号。



2. 配置 部署项目的方式直接将项目放到webapps目录下
(使用的较多,方便,针对小项目)
  • /hello:项目的访问路径--> 虚拟目录
  • 简化部署:将项目打包为war包,再将war包放到webapps目录下
    • war包会自动解压缩


配置conf/server.xml文件
(强烈不建议使用)
在<Host>标签体中配置 <Context docBase="D:/hello" path="/hehe" />
docBase 项目存放的位置,path虚拟目录
热部署
在conf/Catalina\localhost创建任意名称的xml文件,在文件中编写
<Context docBase="D:\hello">
  • 虚拟目录:xml文件的名称  热部署,想删除,修改扩展名为xxx_bat即可

3. 静态项目和动态项目1. java动态项目的目录结构-- 项目的根目录
    -- WEB-INF目录
        -- web.xml:web项目的核心配置文件
        -- classes目录: 放置字节码文件的目录
        -- lib目录: 放置依赖的jar包
2. Tomcat 集成到idea
集成到idea,常见javaEE的项目,部署项目
热部署,如何集成到idea
3. Servlet1. 概念:
运行在服务器端的小程序
servlet就是一个接口,定义了java类被浏览器访问到(tomcat识别)的规则
一个Java类,要想被浏览器访问到(Tomcat识别到),必须实现servlet接口
我们自己定义一个类,实现Servlet接口,复写方法
2. 快速入门
  • 创建javaEE项目
  • 定义一个类,实现servlet接口
    public class ServletDemo01 implements Servlet
  • 实现接口中的抽象方法
  • 配置servlet

        <!--配置servlet-->
        <servlet>
            <servlet-name>demo1</servlet-name>
            <servlet-class>cn.itcast.web.servlet.ServletDemo01</servlet-class>
        </servlet>

        <servlet-mapping>
            <servlet-name>demo1</servlet-name>
            <url-pattern>/demo1</url-pattern>
        </servlet-mapping>
    </web-app>
3. 执行原理
  • 当服务器接收到客户端浏览器的请求后,会解析请求url路径,获取访问的servlet的资源路径
  • 查找web.xml文件,是否有对应的<url-pattern>标签体内容
  • 如果有,则再找对应的<servlet-class>全类名
  • Tomcat会将字节码文件加载进内存Class.forName("全类名"),并且创建其对象cls.newInstance()
  • 调用service方法

4. servlet的生命周期1. 被创建
执行init方法,只执行一次
  • servlet什么时候被创建?
    • 默认情况,第一次被访问时,创建
    • 可以配置指定servlet的创建时机
      • 在servlet标签下配置



指定servlet的创建时机
  • 第一次被访问时,创建<load-on-startup>值为负数
  • 在服务器启动时,创建<load-on-startup>值为0或者正数

servlet的init方法,只执行一次,说明一个servlet在内存中只存在一个对象,servlet是单例的
  • 多个用户同时访问时,可能存在线程安全问题
  • 解决:尽量不要在servlet中定义成员变量,即使定义成员变量,也不要对值进行修改

2. 提供服务
执行service方法,执行多次
3. 被销毁
执行destroy方法,只执行一次
只有服务器正常关闭时,才会执行,一般用于释放资源
5. servlet3.0
好处:支持注解配置,可以不需要web.xml
步骤:
  • 创建JavaEE项目,选择Servlet版本3.0以上,可以不创建web.xml
  • 定义一个类,实现servlet接口
  • 复写方法
  • 在类上使用@WebService注解,进行配置  @WebServlet("资源路径")

6. IDEA与Tomcat的相关配置
  • IDEA会为每一个Tomcat部署的项目单独建立一份配置文件
    • 查看控制台的log:"C:\Users\Lenovo.IntelliJIdea2018.3\system\tomcat_javaweb2"

  • 工作空间项目 和  Tomcat部署的web项目
    • Tomcat真正访问的是“Tomcat部署的web项目”,而“Tomcat部署的web项目”对应着“工作空间项目”的web目录下的所有资源
    • WEB-INF目录下的资源不能被浏览器直接访问


7. servlet相关配置
  • urlpattern: servlet访问路径
    • 一个servlet可以定义多个访问路径:@WebServlet({"/d4","/dd4","/ddd4"})
    • 路径定义规则:
      • /xxx: 路径匹配 "/demo1"
      • /xxx/xxx : 多层路径,目录结构 "/user/demo1"
      • *.do: 扩展名匹配 *.action   为什么写.do呢?

    • 优先级: 绝对匹配 /xxx > /* >  *.do


file://C:/Users/Lenovo/Desktop/java%E5%9F%BA%E7%A1%80%E5%BF%85%E8%83%8C%E7%9F%A5%E8%AF%86%E7%82%B9/img/url_pattern.png?lastModify=1553751539
servlet的体系结构
genericServlet类:将servlet接口中其他方法做了默认空实现,只将service()方法作为抽象
将来定义servlet类时,可以继承GenericServlet,实现service()方法即可
HttpServlet: 对http协议的封装,简化操作
  • 定义继承

Ctrl+H  查看继承

GenericServlet类:
public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();//调用init()方法,将init()方法里的方法体内容输出
    }

public void init() throws ServletException {
  }
Servlet接口:
public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}
public abstract class HttpServlet extends GenericServlet  
为什么GenericServlet重写了Servlet的init方法后,自己又写了个空参的init()方法
day14-18 HTTP1. 概念
Hyper Text Transfer Protocol超文本传输协议
传输协议:定义了客户端和服务器端通信时,发送数据的格式
特点:
  • 基于TCP/IP的高级协议
  • 默认端口:80
  • 基于请求/响应模型的:一次请求对应一次响应
  • 无状态的:每次请求之间相互独立,不能交互数据

历史版本
  • 1.0:每一次请求都会响应都会建立新的连接
  • 1.1:复用连接

发展史:
  • 0.9版本:只能传输HTML,只支持get命令,基于TCP
  • 1.0版本:1996年,不仅可以传输HTML的文本,
  • 1.1版本:1997年,增加持久连接
  • 2.0版本:做了多工的处理

在java开发中不管用线程,数据库,网路请求,建立的连接,都是宝贵的,不要随意乱用和浪费
2. request1. request消息数据格式
file://C:/Users/Lenovo/Desktop/java%E5%9F%BA%E7%A1%80%E5%BF%85%E8%83%8C%E7%9F%A5%E8%AF%86%E7%82%B9/img/%E5%9B%BE%E4%B8%80%20HTTP%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%AF%B7%E6%B1%82%E9%83%A8%E5%88%86.bmp?lastModify=1553751539
1. 请求行
请求方式  请求url  请求协议/版本
GET /login.html  HTTP/1.1
2. 请求头
客户端浏览器告诉服务器一些信息
请求头名称:请求头值
常见的请求头:
  • User-Agent: 浏览器告诉服务器,我访问你使用的浏览器版本信息
    • 可以在服务器端获取该头的信息,解决浏览器的兼容性问题

  • Referer: http://localhost/login.html
    • 告诉服务器,我(当前请求)从哪里来
    • 作用:1. 防盗链 2. 统计工作


3. 请求空行
空行,分隔post请求头和请求体
4. 请求体(正文)
封装POST请求消息的请求参数的
字符串格式

        POST /login.html    HTTP/1.1
        Host: localhost
        User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
        Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
        Accept-Encoding: gzip, deflate
        Referer: http://localhost/login.html
        Connection: keep-alive
        Upgrade-Insecure-Requests: 1
2. request对象1. request对象和response对象的原理
  • request和response对象是由服务器创建的,我们来使用它们
  • request对象是来获取请求消息,response对象是来设置响应消息

  • Tomcat服务器会根据请求url中的资源路径,创建对应的servletDemo1的对象
  • Tomcat服务器,会创建request和response对象,request对象中封装请求消息数据
  • Tomcat将request和response对象传递给service方法,并且调用service方法
  • 程序员,可以通过request对象获取请求消息数据,通过response对象设置响应消息数据
  • 服务器再给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据

2. request对象的继承体系结构
ServletRequest  --接口
    |
HttpServletRequest  -- 接口
    |
org.apache.catalina.connector.RequestFacade类实现

3. request功能1. 获取请求行消息数据
获取请求行数据 GET /day14/demo1?name=zhangsan HTTP/1.1
  • 获取请求方式  GET   String getMethod()
  • 获取虚拟目录  /day14    String getContextPath()
  • 获取Servlet路径  /demo1  String getServletPath()
  • 获取get方式请求参数 name=zhangsan  String getQueryString()
  • 获取请求URI:  /day14/demo1   
    • String getRequestURI()   /day14/demo
    • String getRequestURL()  http://localhost/day14/demo

  • 获取协议及版本:HTTP/1.1    String getProtocol
  • 获取客户机的IP地址:  String getRemoteAddr()

2. 获取请求头数据
方法:
  • String getHeader(String name)  通过请求头的名称获取请求头的值
  • Enumeration<String> getHeaderNames()  获取所有的请求头名称

3. 获取请求体数据
请求体:只有post请求方式,才有请求体,在请求体中封装post请求的请求参数
步骤:
  • 获取流对象
    • BufferedReader getReader()  : 获取字符输入流,只能操作字符数据
    • ServletInputStream getInputStream():  获取字节输入流,可以操作所有数据,在文件上传知识点讲解

  • 再从流对象中拿数据

4. 其他功能4.1获取请求参数通用方式
  • String getParameter(String name)  根据参数名称获取参数值
  • String[] getParameterValues(String name)  根据参数名称获取参数值的数组,常见复选框
  • Enumeration<String> getParameterNames()  获取所有请求的参数名称
  • Map<String, String[]> getParameterMap()  获取所有参数的map集合

  • 中文乱码问题:
    • get方式:Tomcat 8已经将get方式乱码问题解决了
    • post方式:会乱码  
    • 解决:在获取参数之前,设置request的编码方式request.setCharacterEncoding("utf-8");


4.2 请求转发
一种在服务器内部的资源跳转方式
请求次数:代表的是浏览器到服务器端的次数,不包含服务器内部跳转
  • 步骤:
    • 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
    • 使用RequestDispatcher对象来进行转发:forward(ServletRequest request,ServletResponse response)

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


4.3 共享数据
  • 域对象:一个有作用范围的对象,可以在范围内共享数据
  • request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
  • 方法:
    • void setAttribute(String name,Object obj) 存储数据
    • Object getAttribute(String name) 通过键获取值
    • void removeAttribute(String name)  通过键移除键值对


4.4 获取ServletContext
  • ServletContext getServletContext()

3. request案例1. 用户登录案例需求:
1.编写login.html登录页面
    username & password 两个输入框
2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表
3.使用JdbcTemplate技术封装JDBC
4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您
5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误
2. 分析
file://C:/Users/Lenovo/Desktop/java%E5%9F%BA%E7%A1%80%E5%BF%85%E8%83%8C%E7%9F%A5%E8%AF%86%E7%82%B9/img/%E6%A1%88%E4%BE%8B%E5%88%86%E6%9E%90.png?lastModify=1553751539
3. 开发步骤
  • 创建项目,导入HTML项目,配置文件,jar包
  • 创建数据库环境

    CREATE DATABASE day14;

    USE day14;

    CREATE TABLE USER(

        id INT PRIMARY KEY AUTO_INCREMENT,
        username VARCHAR(32) UNIQUE NOT NULL,
        PASSWORD VARCHAR(32) NOT NULL
    );
  • 创建包cn.itcast.domain创建类User
  • 创建包cn.itcast.dao 创建类UserDao 操作数据库,提供login的方法
  • 创建工具吧con.itcast.util创建JDBCUtils工具类,使用Druid连接池,获取连接池对象和连接对象

    public class JDBCUtils {
        private static DataSource ds;

        static {
            try {
                // 加载配置文件
                Properties pro = new Properties();
                InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
                pro.load(in);
                // 初始化连接池对象
                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();
        }
    }
  • 完善UserDao的方法

    public class UserDao {

        // 声明JDBCTemplate对象共用
        private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

   /**
    *  登录方法
    * @param loginUser 只有用户名和密码
    * @return user包含用户全部数据,没有,返回null值
    */
   public User login(User loginUser){
       try {
           // 1. 编写SQL
           String sql = "select * from user where username = ? and password = ?";
           // 2. 调用query方法
           User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), loginUser.getUsername(), loginUser.getPassword());
           return user;
       } catch (DataAccessException e) {
           e.printStackTrace();//记录日志
           return null;
       }
   }
   }


7. 测试方法,看Dao代码运行是否正常,创建包`cn.itcast.test`,测试类`UserDaoTest`

   ```java
   public class UserDaoTest {
       @Test
       public void testLogin(){
           // 创建登录用户对象
           User loginUser = new User();
           loginUser.setUsername("superbaby");
           loginUser.setPassword("123111");

           // 查看数据库是否有该对象
           UserDao dao = new UserDao();
           User user = dao.login(loginUser);
           System.out.println(user);

       }
   }
   发现问题,如果用户名密码不一致,会出现异常,不应该抛出异常,应该返回null,用try/catch包裹(ctrl+alt+t)
  • 编写cn.itcast.web.servlet.LoginServlet类

    @WebServlet("/loginServlet")
    public class LoginServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 设置编码
            request.setCharacterEncoding("utf-8");
            // 获取请求参数
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            // 封装user对象
            User loginUser = new User();
            loginUser.setUsername(username);
            loginUser.setPassword(password);

            // 调用Dao的login方法
            UserDao dao = new UserDao();
            User user = dao.login(loginUser);

            // 判断user
            if(user == null){
                //登录失败
                //转发
                request.getRequestDispatcher("/failServlet").forward(request,response);
            }else{
                // 登录成功
                // 存储数据
                request.setAttribute("user",user);
                request.getRequestDispatcher("/successServlet").forward(request,response);
            }
        }

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request,response);
        }
    }
  • 编写成功和失败的跳转页面

    @WebServlet("/failServlet")
    public class FailServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            // 给页面写一句话
            // 设置编码
            response.setContentType("text/html;charset=utf-8");
            // 输出
            response.getWriter().write("登录失败,用户名或密码错误");
        }

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request,response);
        }
    }
   @WebServlet("/successServlet")   public class SuccessServlet extends HttpServlet {

   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // 获取request域中共享的user对象
       User user =(User) request.getAttribute("user");
       if (user!=null) {
           // 给页面写一句话
           // 设置编码
           response.setContentType("text/html;charset=utf-8");
           // 输出
           response.getWriter().write("登录成功,"+user.getUsername()+"欢迎您!");
       }
   }

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


### 4. 错误日志

问题:登录后跳转找不到网页,转不到loginServlet的页面

解决方法:部署的问题,在idea该项目的部署中,将虚拟目录改为`/day14_test`,之前误改为`/day14`

### 5. 优化

使用Apache的BeanUtils包封装loginUser对象,修改部分如下

```java
/*// 获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 封装user对象
        User loginUser = new User();
        loginUser.setUsername(username);
        loginUser.setPassword(password);*/

        // 2. 获取所有请求参数
        Map<String, String[]> map = request.getParameterMap();
        // 3. 创建User对象
        User loginUser = new User();
        // 3.2 使用BeanUtils封装
        try {
            BeanUtils.populate(loginUser,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }6. BeanUtils工具类
简化数据封装,用于封装JavaBean,原理:内省机制
1. J

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马