Tomcat

Tomcat

Tomcat是一个由Apache基金组织开发的免费开源Web服务器。

软件安装

资料中已经提供好绿色解压版,直接解压即安装,要求安装目录没有中文,没有空格

logs: 日志

webapps: 放置web资源的

启动和停止

启动

Tomcat启动:安装目录/bin/startup.bat 双击文件即可

浏览器访问: http://localhost:8080 (localhost指的是本机地址,8080是tomcat的默认访问端口号)

启动问题

* 现象:黑窗口一闪而过
* 原因:Tomcat是java编写,启动时依赖JAVA_HOME环境变量
* 解决:正确配置JAVA_HOME环境变量和PATH路径

电脑环境变量中含有两个以 Catalina-* 需要删掉

* 报错: 启动过程中,持续一段时间,然后窗口退出,查看tomcat的日志,提示下面内容:Address already in use: JVM_Bind  
* 原因: tomcat端口被占用
* 解决:
    方式一:暴力杀掉占用端口的进程
        1)使用cmd启动dos窗口,使用命令【 netstat -ano | findstr 端口号 】找到占用的端口号的对应进程
        2)使用【 taskkill /pid 进程号 】杀死进程 
    方式二:修改当前Tomcat的端口号
        修改Tomcat安装目录/conf/server.xml文件中的三个端口号8005  8080  8009]  
        注意: 修改的端口号在1025~65535之间 (65535为最大端口号, 0~1024:系统预留的端口号)

停止

* 方式1: 安装目录/bin/shutdown.bat双击文件即可
* 方式2: 直接关闭tomcat的运行窗口

项目部署

项目部署指的是如何将我们自己开发好的项目部署到tomcat中,然后对外提供访问。

创建一个本地项目,然后复制到tomcat的webapps目录下

项目结构

* tomcat所能识别的项目结构如下: 
    |-myapp(web工程)
        |--静态资源目录: css、js、html、image
        |--WEB-INF目录 (这下面的资源,无法直接通过浏览器访问)
            |--classes   程序的.class文件
            |--lib       依赖的jar包存放的文件
            |--web.xml   web项目配置文件
        |--index.jsp(index.html) 项目首页

项目开发(掌握)

本小节我们学习如何利用idea开发一个Java项目,并把它部署到tomcat中运行

配置Tomcat模板

我们需要在Idea中配置一个Tomcat的模板配置,这样以后使用tomcat就不用每次都重新配置了,这个步骤只需要做一次

创建模块

注意:使用idea创建的maven是一个Java版本, 我们要想在项目中开发html页面,需要将它转换为一个web版本的工程

① 创建Java版本项目

② 安装JBLToJavaWEb插件

③ 转换为web版本的项目

④ 最后结果

创建项目资源

在项目中创建HTML页面

部署项目到Tomcat

将编写的项目部署到Tomcat服务器

这种报错就是端口冲突,一般重启电脑即可解决

启动Tomcat测试

在idea中启动tomcat,测试项目

WEB-INF目录下的资源不允许使用浏览器直接访问

HTTP协议(理解)

HTTP协议介绍

* HTTP (Hyper Text Transfer Protocol) 超文本传输协议,是互联网上应用最为广泛的一种网络协议。   
    作用:
        规范浏览器和服务器之间通信时传输数据的格式
    特点:     
        1) 基于TCP的高级协议,端口号默认80
        2) 基于请求/响应模型:一次请求对应一个响应     
        3) 无状态:每次请求之间都是相互独立的,也就是说HTTP协议本身无法记录上一次访问的数据   

浏览器查看协议

准备页面

修改项目的index.html,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tomcat</title></head>
<body>
<form action="#" method="get"> 
    姓名:<input type="text" name="username"><br> 
    密码:<input type="text" name="password"><br>
    <input type="submit" value="提交"></form>
</body>
</html>

请求访问

以Chrome浏览器为例,使用F12打开开发者模式,选择NetWork选项卡,然后通过网络访问上面的index.html页面

HTTP请求

查看HTTP请求

HTTP的请求是由行、头、体构成的。

请求行

* POST    /day03-tomcat/index.html     HTTP/1.1
    请求行由三部分组成:请求方式  请求路径  请求协议/版本。
    请求方式有很多, 我们需要关注两种: get 和 post   
        get     
            1)请求参数在地址栏显示,不太安全
            2)请求参数大小有限制
            3)没有请求体
        post        
            1)请求参数没有在地址栏显示,而是在请求体显示,相对安全
            2)请求参数大小没有限制
            3)有请求体

请求头

* Connection: keep-alive
    请求头格式是键值对  键:值  
    User-Agent: 浏览器告诉服务器端,客户端操作系统和浏览器版本信息,借助它可以处理浏览器的兼容性问题

请求体

* username=heima
	格式 参数名=参数值&参数名=参数值	
	注意 get方式没有请求体,post方式有请求体

HTTP响应

查看HTTP响应

HTTP的响应也是由行、头、体构成的。

响应行

* HTTP/1.1  200  OK
	响应行由三部分组成: 协议/版本  响应码  响应描述
	常见状态码:由服务器告诉浏览器,本次请求响应状态码说明	
        200:操作成功
        404:请求路径没有对应资源
        500: 服务器错误

响应头

* Last-Modified: Wed, 22 May 2019 06:50:39 GMT
	常见响应头	
        Content-Type:服务器告诉浏览器,响应体的数据类型和编码方式		
    	Content-Type: text/html;charset=utf-8

响应体

 * 浏览器内核解析展示到页面的内容

Servlet(重点)

简介

Servlet: Server Applet,翻译为运行在服务端的Java小程序,是sun公司提供一套规范( 接口 ),用来定义我们的代码怎么写才能被tomcat识别。

本质:接口,一个类想要被tomcat正确识别,那么这个类就必须直接或间接的实现Servlet接口。

任务:接收请求,处理请求,返回响应。

入门案例

需求:使用一个Servlet完成一个功能,接收浏览器请求,在服务器控制台打印出访问时间的同时将时间写回浏览器。

创建模块

    <!--servlet-->
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>
    </dependencies>

编写servlet

配置servlet

部署测试

执行流程

* 访问流程:
1. 当Tomcat接收到客户端浏览器的请求后,会解析出Servlet的资源路径
2. 查找web.xml文件,是否有对应的 <url-pattern></url-pattern> 标签体内容
3. 如果有,则在找到对应的 <servlet-class></servlet-class> 全限定名
4. tomcat根据类的全限定名,将字节码文件加载进内存,并且创建其对象
5. 调用service()方法 

细节介绍

API

* 重点	
	init(ServletConfig config):会在serlvet对象创建之后马上执行,只执行一次	
	service(ServletRequest req, ServletResponse res):会被调用多次,每次处理请求都会调用该方法	
	destroy():会在servlet被销毁之前执行,只执行一次

* 了解	
	getServletInfo(): 获取serlvet的信息	
	getServletConfig():获取servlet配置信息

① 三个重点方法

② 设置测试

③ 获取配置参数

package com.itheima.servlet;

import javax.servlet.*;
import java.io.IOException;
import java.util.Date;

//自定义一个Servlet, 一个类想要被tomcat正确识别,那么这个类就必须直接或间接的实现Servlet接口
public class TimeServlet implements Servlet {

    private ServletConfig servletConfig = null;

    //初始化 此方法会在当前对象创建之后自动调用,而且仅仅会调用一次

    //tomcat会将读取的配置内容封装到ServletConfig对象中,并且将这个对象作为参数,传入init方法
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("当前对象创建完毕了........");
        this.servletConfig = servletConfig;
    }

    //这个方法是我们浏览器每次请求到达服务器之后,就会自动被调用的一个方法
    //ServletRequest: Tomcat会将浏览器发送过来的请求的行头体封装到这个对象中
    //ServletResponse: Tomcat创建出来用于返回给浏览器的响应对象
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //1. 获取到当前时间
        String date = "当前时间:" + new Date().toLocaleString();

        //2. 打印时间
        System.out.println(date);

        //3. 将时间写回浏览器
        //响应头的作用是告诉浏览器,当前返回内容的格式和编码
        servletResponse.setContentType("text/html;charset=" + this.servletConfig.getInitParameter("encoding"));
        servletResponse.getWriter().write(date);
    }

    //销毁 次方法会在当前对象销毁之前自动调用,而且仅仅会调用一次
    public void destroy() {
        System.out.println("当前对象即将销毁了........");

    }

    //返回当前servlet中配置信息
    public ServletConfig getServletConfig() {
        return this.servletConfig;
    }

    //返回当前servlet的介绍
    public String getServletInfo() {
        return "这是一个返回当前服务器时间的servlet";
    }
}

生命周期

* 生命周期: 指的是一个Servlet从创建--->提供服务--->销毁的这个过程。  
	1. 创建(只一次):        默认情况下,servlet第一次被访问的时候创建,创建之后立即执行init()方法进行初始化  
	2. 提供服务(可以多次):   servlet每次被访问都会执行service()方法对外提供服务  
	3. 销毁(只一次):        当tomcat服务器要正常关闭时,会销毁servlet,在servlet销毁之前会调用destory()方法

* 创建时机	
	1. 默认情况下,servlet会在第一次被访问的时候创建	
	2. 但是也只是通过配置的形式来将创建时机提前到Tomcat启动的时候		
	<load-on-startup> 数字 </load-on-startup> 用来修改servlet的创建时机			
		负  数:Servlet在第一次被访问时创建			
		非负数:Servlet在tomcat启动的时候创建,范围: 0-10,值越小优先级越高

路径匹配(了解)

1. servlet支持以下几种路径匹配模式:       
	完全匹配(/a/helloServlet.do):  可以匹配到一个完整的路径,必须以`/`开始       
	目录匹配(/a/*):  可以匹配到一个目录下的所有路径,必须以`/`开始,必须以`*`结束
	后缀匹配(*.do):  可以匹配到以指定后缀结尾的路径,不能以`/`开始,必须以`.xxx`结束
	默认匹配(/):     代表这是一个默认的servlet,当一个请求无法被任何一个servlet匹配上时,进入到此servlet
2. 注意:上面四个配置优先级依次降低,一旦匹配中其中一个,就不会再去匹配其它的了

体系结构(了解)

* Servlet接口                   这是Servlet的根接口,所有的Servlet都必须直接或间接的实现它   
* |---GenericServlet抽象类      这是一个抽象类,它实现了Servlet接口中的大部分方法,只剩下了一个service方法等待我们实现
* |------HttpServlet抽象类      这是一个专门用来处理http请求的类,在这个类中可以轻松的对不同的请求类型进行处理

① GenericServlet使用

② HttpServlet使用(掌握)

注解版

* @WebServlet
    name:指定servlet名称,等价于web.xml中的servlet-name,如果省略,则为Servlet的完整类名
    urlPatterns:配置请求路径映射,等价于web.xml中的urlPatterns
    loadOnStartup:指定Servlet的加载顺序,等价于web.xml中的load-on-startup

常见报错

1. The servlets named [annoServlet] and [annoServlet2] are both mapped to the url-pattern [/annoServlet] which is not permitted	
	两个servlet的路径重复
2. Invalid url-pattern [annoServlet] in servlet mapping  
	servlet路径不是/开头的

RequesResponse

Reques

请求头

* 请求行例子:  
	GET /day04-request/requestLine?name=zs  HTTP/1.1
	请求方式   请求路径   请求参数    协议/版本

* 重要方法:
1. String getMethod()       获取请求方式
2. String getRequestURL()   获取请求完整路径(URL)
3. String getRequestURI()   获取请求资源部分(URI)
4. String getContextPath()  获取项目虚拟目录  [记住]
5. String getServletPath()  获取项目资源路径

请求头(了解)

* 请求头例子:  
	User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36

* 重要方法:
	String getHeader(String name)    以String的形式返回指定请求头的值

使用一个案例说明请求头的使用: 判断发送请求的浏览器的类型

* 谷歌 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36
* 火狐 Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0

请求参数的位置:

get请求: URL上 ​ post请求: 请求体中

  • 请求参数例子: name=张三&age=18&hobby=抽烟&hobby=喝酒&hobby=烫头

  • 重要方法:

    1. String getParameter(String name) 根据参数名获得参数值(单个)

    2. String[] getParameterValues(String name) 根据参数名获得参数值(数组)

      1. Map<String, String []> getParameterMap() 获得所有的参数,封装到Map集合

将请求参数封装成实体

* BeanUtils是apache提供的一个工具包
* 它提供了一个方法:populate,使用这个方法可以请求的将Map转成一个实体对象  BeanUtils.populate(Object obj,Map map);
* 需要注意的是,map中的key要和实体类中的属性保持一致

准备实体类

必须和数据库相对应

添加依赖

<dependency>            
    <groupId>commons-beanutils</groupId>            
    <artifactId>commons-beanutils</artifactId>            
    <version>1.8.3</version>        
</dependency>

接收参数

Map(String,String[]) map=req.getParamterMap();
User user = new User();
try(){
BeanUtils.populate(user,map);
}catch()

Response

转发

req.getRequestDispatcher("下一步地址[仅仅写资源路径]").forward(req, resp);  //请求转发

重定向

1. 方式一:
	response.setStatus(302);
	response.setHeader("Location", 目标资源位置);

2. 方式二:
	response.sendRedirect(目标资源位置)
	特点:
1. 地址栏发生改变
2. 重定向到服务器外部资源
3. 重定向是两次请求
4. 不能使用request域共享数据

request域

* Request是一个域对象,可以存储数据,一般用于在一次请求之间进行数据共享
* 常见方法:
	void   setAttribute(String name, Object value)	   向request域放入数据 
	Object getAttribute(String name)                   根据name从向request域获取数据
	void   removeAttribute(String name)                根据name从request域删除数据 

request生命周期

1. 何时创建:Tomcat接收到一个请求,在调用service方法之前创建request对象
2. 何时销毁:当一个请求离开服务器(响应回到浏览器)的时候,Tomcat就会销毁这个对象
3. 作用范围:一次请求中

相应头

* 响应行
	响应行格式例子:
		HTTP/1.1  200   OK
		HTTP/1.1  302   OK
	设置响应行: 	
		void setStatus(int sc)

* 响应头
	响应头格式例子:
		Location:http://www.baidu.com
		Content-Type:text/html;charset=utf-8
	设置响应头:
		void setHeader(String name, String value)

* 响应体
	通过response获取输出流
		字符流:PrintWriter getWriter() 
		字节流:ServletOutputStream getOutputStream()
	注意:在同一个servlet中,不能同时使用字节流和字符流

向浏览器输出字符

* 使用字符流输出内容到浏览器
	PrintWriter writer = response.getWriter();
	writer.write("字符串");
* 统一设置服务器和浏览器编码格式
	resp.setHeader("content-type","text/html;charset=utf-8")   了解
	resp.setContentType("text/html;charset=utf-8")             推荐

hutool

加入hutool的依赖**

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.4.3</version>
</dependency>

② java生成验证码

package com.itheima.servlet;

import cn.hutool.captcha.LineCaptcha;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/codeServlet")
public class CodeServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 生成验证码图片
        LineCaptcha lineCaptcha = new LineCaptcha(300, 150);
        System.out.println("验证码:" + lineCaptcha.getCode());

        //2. 将图片以字节流的形式写回浏览器
        lineCaptcha.write(resp.getOutputStream());
    }
}

③ html显示验证码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img src="/day09-response/codeServlet">
</body>
</html>

可见登录案例

day09-login

会话

cookie

* Cookie常用的API
	创建Cookie: Cookie cookie = new Cookie(key,value)
	写回Cookie: resp.addCookie(cookie)
	获取Cookie: Cookie[] cookies = request.getCookies()

代码实现

		生成cookie
		req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        String product = req.getParameter("product");
        Cookie cookie = new Cookie("product", product);
        resp.addCookie(cookie);
        resp.getWriter().write("加入购物车成功");

接收cookie

 		req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        Cookie[] cookies = req.getCookies();
        if (cookies == null && cookies.length == 0) {
            resp.getWriter().write("未找到购物车产品");
            return;
        }
        for (Cookie cookie : cookies) {
            if ("product".equals(cookie.getName()))
                resp.getWriter().write("购物车产品: " + cookie.getValue());
            return;
        }
        resp.getWriter().write("未找到购物车产品");

执行原理

* Cookie的工作是基于HTTP的请求头和响应头的设置实现的
	响应头:Set-Cookie:product=XiaoMi   
	请求头:Cookie:product=xiaomi  
    
* 执行流程
	1. 浏览器向服务器发送一个添加购物车请求
	2. 服务请创建一个Cookie,并通过response对象将Cookie写回浏览器(通过Set-Cookie响应头)
	3. 浏览器接收到这个响应头之后,会取出里面的信息,存储在自己的cookie空间中
	4. 当浏览器发送查询请求的时候,会将cookie中的信息携带到服务器中(通过Cookie请求头)
	5. 服务器接收到请求之后,就可以通过request对象获取到请求头中的所有Cookie了

* 问题:Cookie是否可以存储中文和特殊字符?
* 回答:在tomcat8版本之前不支持中文;在tomcat8版本之后支持中文,但是不支持一些特殊符号,比如说分号、逗号、空格等
		如果存储了,会出现错误:An invalid character [32] was present in the Cookie value
	   为了更好的存储数据,推荐在向cookie中存储数据之前,先进行编码处理;需要使用的时候,从cookie中读取之后再解码,对应的API如下:
		URLEncoder类:static String encode(String s, String enc)  将指定的字符串,按指定的编码表编码
		URLDecoder类:static String decode(String s, String enc)  将指定的字符串,按指定的编码表解码

有效时长

* 问题:cookie的存活时长是多少?
* 回答:默认情况下,cookie会随着浏览器的关闭而销毁,但是可以通过使用cookie.setMaxAge(时长)来设置,时长参数支持:
		负数: 随着浏览器的关闭而销毁
		正数: 代表存活多少s(跟浏览器是否关闭无关)
		0: 立即销毁

cookie小总结

1. cookie基本原理
	创建在服务器,保存在浏览器,用于记录一次会话中的请求和响应的信息
	使用的头:
		响应头: 服务器向浏览器保存cookie     Set-Cookie:product=xiaomi   
		请求头:浏览器向服务器报告cookie     Cookie:product=xiaomi   
2. api
	1) 创建cookie: new Cookie(key,value)
		设置存活时间: cookie.setMaxAge(正整数时长)
		中文和字符: 使用编码和解码技术 URL
	2) 将cookie写回浏览器: resp.addCookie(cookie)
	3) 从请求中获取cookie: req.getCookies()
	
3. Cookie特点
	1. cookie存储数据在客户端(浏览器)
	2. cookie只能存储字符串
	3. cookie单个大小不能超过4KB

Session

执行原理

* Session的工作是依赖于Cookie的,也要基于HTTP的请求头和响应头的设置实现的
	响应头:Set-Cookie: JESESSIONID=B72574042864B9C7C319684D269BA7C7
	请求头:Cookie: JESESSIONID=B72574042864B9C7C319684D269BA7C7
	 
* 执行流程
	1. 浏览器向服务器发送一个添加购物车请求
	2. 服务请创建一个Session
	3. 通过程序向Session中添加商品信息
	4. 服务器通过response将session的唯一标识JESESSIONID写回到浏览器的Cookie中(通过Set-Cookie响应头)
	5. 当浏览器发送查询请求的时候,会将cookie中的JESESSIONID信息携带到服务器中(通过Cookie请求头)
	6. 服务器接收到请求之后,通过session的唯一标识定位到session
	7. 我们就就可以通过程序从session获取信息了

代码实现

创建session

req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        String product = req.getParameter("product");
        HttpSession session = req.getSession();
        String encode = URLEncoder.encode(product);
        session.setAttribute("product",encode);
        //内部默认执行步骤
//        String sessionId = session.getId();
//        Cookie cookie = new Cookie("JESESSIONID", sessionId);
//        resp.addCookie(cookie);

        resp.getWriter().write("加入购物车成功");

接受session

req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //内部默认执行步骤
//        Cookie[] cookies = req.getCookies();
//        if (cookies==null&&cookies.length==0){
//            return;
//        }
//        for (Cookie cookie : cookies) {
//            if (!"JESESIONID".equals(cookie.getName())){
//                return;
//            }
//
//        }
        HttpSession session = req.getSession();
        String encode = (String) session.getAttribute("produce");
        String product = URLDecoder.decode(encode);
        resp.getWriter().write("购物产品:"+product);

钝化与活化

* 服务器重启,Session数据会不会丢失呢?
* 默认不会,因为服务器在关闭的过程中会将seesion信息保存到磁盘,启动的过程中再从磁盘读取回来,这两个过程分别称为钝化和活化
	钝化:我们tomcat服务器在关闭时,将内存的session数据,序列化到磁盘文件
	活化:我们tomcat服务器在重新启动时,将磁盘文件反序列化到服务器内存中...
* 前提条件,我们存放的对象,必须实现序列化接口...

销毁

* session会在下面三种情况下销毁
	1) 用户非活跃状态30分钟(可以调整)
		<session-config>
			<session-timeout>30</session-timeout>
         </session-config>
	2) 服务器非正常关闭(服务器没有时间做钝化)
	3) 使用程序销毁 session.invalidate()

小结

1. session基本原理
    创建服务器,保存在服务器,用于记录一次会话中的请求和响应的信息
    使用的头:
		响应头: 服务器向浏览器保存cookie     Set-Cookie:JESESSIONID=session标识   
		请求头:浏览器向服务器报告cookie     Cookie:JESESSIONID=session标识  
        
2. api
	1) 创建Session: req.getSession()
	2) 向session中保存数据:setAttribute(key,value)
	3) 从session中获取数据:getAttribue(key)
	4) 摧毁session:session.invlidate()
	
3. sessione特点
    1. session存储数据在服务器
    2. session存储类型任意
    3. session存储大小和数量没有限制
    4. session存储相对安全

jsp技术

JSP(Java Server Pages)是SUN公司在Servlet的基础上推出的一种技术,它将Java代码和HTML语句混合在同一个文件中编写

* <%  Java代码  %>  
	jsp脚本作用: 在jsp中编写逻辑Java代码,这里面编写的代码, 编译之后会直接出现在servlet的service()方法中
<!-- jsp -->
  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
  </dependency>

运行流程

JSP本质上就是一个Servlet,其真正运行之前是要先转换成Servlet的。

1. 客户端发出请求
2. web容器将jsp转化为servlet代码(.java)
3. web容器将转化为servlet代码编译(.class)
4. web容器加载编译后的代码并执行
5. 将执行结果响应给客户端

EL表达式

EL(Expression Language)表达式语言,主要用来简化jsp中对java代码的操作,它可以从jsp的域对象中获取数据

语法:${表达式}

JavaWeb中目前我们有用的有两大域对象,分别是:

  • request:当前请求有效

  • session:当前会话有效

el 表达式获取数据,会依次从这2个域中寻找,直到找到为止。

* 获取精准域中数据
	${requestScope.键名}       从HttpServletRequest域中获取
	${sessionScope.键名}       从HttpSession域中获取

* 简化写法
	${键名}   按照上面的域范围从小到大依次从2个域中进行查找;如果从某一个域中找到了,立即返回;如果2个域中都没有,则返回空
	* 获取不同类型的数据:
	简单类型:${键名}
	对象类型:${键名.属性名}
	集合类型:${键名[索引]}

JSTL表达式

JSTL (Jsp Standard Tag Library)Jsp标准标签库,是一套由Apache组织开源的jsp标签库,用来替换和简化jsp页面中java代码。

<!-- jstl -->
<dependency>
  <groupId>jstl</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

语法

if

* if标签用于单分支条件判断,相当于Java中的`if(条件){}`的用法,它的常见用法如下:
    <c:if test="条件">
    	条件成立的逻辑
    </c:if>
* 注意: 它只有if的功能,没有else的功能,如果需要else,需要自己取反操作

foreach

* forEach用于循环遍历,相当于java中的for关键字,它的常见属性如下:
	begin:设置循环的开始
	end:设置循环的结束
	var:声明循环过程中的临时变量
	step:设置步长——间隔几次循环,执行一次循环体中的内 
	items:指定要循环的对象集合
	varStatus:保存了当前循环过程中的信息(循环的开始、结束、步长、次数等)
	
* forEach标签的主要用法有下面两种:
	1.  增强for循环
		<c:forEach items="数据集合" var="x">
            ${x}
		</c:forEach>
	
	2.  普通for循环
		<c:forEach begin="1" end="10" step="1" var="x">
            ${x}
		</c:forEach>

增强for和普通for

	 for(User user : userList){   
     	user
     }
     
     for(int i = 0; i < 10; i++){
		i
	 }

MVC模式

MVC是Model-View-Controller(模型-视图-控制器)的简称,其主要作用是将视图展示和业务控制代码分离开来。

* Model(模型): 指的就是数据或者数据的来源

* View (视图): 指的就是可视化界面

* Controller(控制器): 控制器作用于模型和视图上,负责请求的调度,它使视图与模型分离开来

三层架构

为了实现代码的层次清晰,分工明确,通常会将一个应用划分成三层架构:表示层、业务逻辑层、数据访问层。

* 表示层(web层):与浏览器进行数据交互

* 业务层(service层): 专门用于处理业务逻辑 

* 持久层(dao层): 与数据库进行数据交换

使用见web/day11

过滤器

流程

* 一个Filter的执行流程:
	1. 客户端向服务器发起访问资源的请求
	2. Filter将请求拦截住,开始处理访问资源之前的逻辑
	3. Filter决定是否要放行访问请求,如果放行,请求继续向后运行
	4. 请求访问到相关资源,然后服务器给出响应
	5. Filter将响应拦截住,开始处理访问资源之后的逻辑
	6. 服务器将响应返回给浏览器

代码

@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=utf-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

生命周期

* 研究Filter的生命周期就是研究它的创建、销毁、工作时机。对应着这三个过程,Filter提供了三个方法:
	init:过滤器的初始化方法,服务器启动的时候执行一次。
	doFilter:当请求满足拦截路径条件时执行,可执行多次。
	destory:过滤器的销毁方法,服务器停止或者将项目从服务器中移除的时候执行一次。

拦截路径

* 在Filter中的url-pattern支持下面的匹配方式:
	1. 精确匹配:直接匹配到某个资源上
	2. 路径匹配:匹配某个目录,要求以/开头,以`*`结尾
	3. 后缀匹配:根据后缀匹配,要求以`*.`开头

注解写法

* 使用注解可以简化xml的配置,常用注解选项如下:
	value 指定拦截的路径,等同于 urlPatterns
	@WebFilter

过滤器链

程序有时需要对同一个资源进行多重过滤,这就可以配置多个过滤器,称为过滤器链。

只有过滤器链中的所有的过滤器都对请求路径放行,请求才能访问到目标资源。

注意

filter xml版本

根据filter-mapping的先后顺序来决定过滤器的顺序, 哪个过滤器的filter-mapping在前面先执行哪个

filter 注解版本

根据过滤器类名称的字符排序,值小的先执行

监听器

	主要监听这三个域对象的创建和销毁以及域对象中存储对象的增加和减少.
	web中的监听器一共有8个(扩展):
        ServletContextListener   监听ServletContext对象的创建和销毁
        HttpSessionListener      监听HttpSession对象的创建和销毁
        ServletRequestListener   监听ServletRequest对象的创建和销毁
        
        ServletContextAttributeListener   监听ServletContext对象的数据的变化
        HttpSessionAttributeListener      监听HttpSession对象的数据的变化
        ServletRequestAttributeListener   监听ServletRequest对象的数据的变化
       
        HttpSessionBindingListener     监听自己被绑定、解绑到HttpSession中
        HttpSessionActivationListener  监听自己被钝化或激活了
    他们的使用方式是基本一致的,我们使用其中的一个(ServletContextListenner)来做演示

使用ServletContextListener来学习下监听器的使用步骤,因为这个监听器是监听器中使用率最高的一个,其它监听器的使用方式都类似。

我们使用这个监听器可以在项目启动和销毁的时候做一些事情,例如,在项目启动的时候加载配置文件。

xml配置

注解配置

JSON

依赖

 <!--jackson-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.1</version>
        </dependency>

概述

JSON(JavaScript Object Notation)翻译为JavaScript对象,这是JS语言的对象表示形式,常用项目前后端之间的信息交互

* java对象表示形式
    User user = new User();
    user.setUsername("后羿");
    user.setAge(23);
    user.setSex("男");
			
* javaScript对象(JSON)表示形式
    {
        "username":"后羿",
        "age":"23",
        "sex":"男"
    }

基础语法

* 对象类型(map  对象)
		{name:value,name:value}   

* 数组类型(数组 list)
		List<String>
		[
			"张三","李四","王五"
		]

		List<User>
		[
            {"name":"zs","age":18},
            {"name":"ls","age":19}
		]

JAVA转换

工具名称介绍
JsonlibJava类库,需要导入的jar包较多
Gsongoogle提供的一个简单的json转换工具
Fastjsonalibaba技术团队提供的一个高性能的json转换工具
Jackson开源免费的json转换工具,springmvc转换默认使用jackson
* Jackson完成数据转换使用的类是ObjectMapper,它有两个主要方法:
	String writeValueAsString(Object obj): 将一个对象转换为json字符串
	T readValue(String json, Class clazz): 将一个字符串转换为指定类型的对象 

代码

private void findByName(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    String name = req.getParameter("name");
    User user=userService.findByName(name);
    try {
    //对象转JSON
        String json = new ObjectMapper().writeValueAsString(user);
        resp.getWriter().write(json);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}


//Json--->Java
    @Test
    public void test1() throws JsonProcessingException {
        //1. 先得到一个对象的JSON串
        String json = "{\"id\":1,\"name\":\"张三\",\"age\":18}";

        //2. 创建ObjectMapper, 实现转换
        User user = new ObjectMapper().readValue(json, User.class);
        System.out.println(user);

    }

java转Json

调用new ObjectMapper().writeValueAsString(user);

Json转java

调用new ObjectMapper().readValue(json, User.class);

AJAX

概述

* AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
* 可以向服务器发送`异步`请求,实现在不重新加载整个网页情况下,更新网页局部的内容,从而提高用户的体验。
	同步:客户端发送请求后,必须等待服务端的响应。在等待的期间客户端不能做其他操作。 
	异步:客户端发送请求后,不需要等待服务器的响应。在服务器处理的过程中,客户端可以进行其他操作。

	异步请求   局部刷新

* 应用场景
	搜索框提示
	表单数据验证 

语法

//axios 发送get请求	
axios.get("url?username=zhangsan&password=123").then(resp=>{
	resp.data;//返回结果
})

// axios发送post请求
axios.post("url",{"username":"zhangsan","password":"123"}).then(resp=>{
	resp.data;//返回结果
})

依赖

<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.1</version>
        </dependency>

Vue概述

MVVM模式

* MVVM是Model-View-ViewModel的简写,它本质上就是MVC的改进版;MVVM就是将其中的View的状态和行为抽象化,让我们将视图UI和业务逻辑分开。
	- M: 即Model,模型,指的就是数据
	- V: 即View, 视图,指的就是页面
	- VM:即View-Model,指的是模型和数据的双向绑定(即view和Model互相影响,Model变了,view随之改变;view变了,Model也随之改变)
	
* MVC和MVVM的使用区别
	在MVC模式中,
		开发人员需要从后端获取到数据(Model),然后通过操作DOM渲染视图(View)。
		如果用户改变了视图(view),开发人员还需要再通过DOM获取改变之后的数据,同步到Model中。
    在MVVM模式中,
    	Model和View是绑定的,Model变了,view自动变化;view变了,Model自动变化。
    	因此,程序员只需要关注Model即可。
    	
* 基于MVVM模式的前端框架三巨头:Vue、React、AngularJS,国内目前非常火的就是:Vue

认识Vue

Vue是一套用于构建用户界面的渐进式框架,一个前端项目可以使用vue一两个特性,也可以整个项目都用vue。

Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。就是将视图和数据分开,v-model进行数据和视图进行交互,完成前端分开处理

Vue的使用也非常简单,直接在需要使用Vue功能的页面直接引入vue.js即可。

Vue对象介绍

// Vue对象的介绍
const app = new Vue({
el: "#app",  // el用于挂载视图,即使用css选择器,选中当前vue可以管理的视图范围,注意: vue选择视图必须使用的是双标签,html和body除外
data:{       // data是一个对象,里面存储的就是视图数据,支持js的各种数据类型(简单  对象  数组)
  message:""
}
})

双向绑定

* v-model是双向绑定,视图(View)和模型(Model)之间会互相影响。
* 目前v-model的可使用元素有:input、select、textarea

属性绑定

* 对于HTML标签属性,如果想要动态传值,不能使用{{}},而应该使用专门的属性绑定语法
	标准语法:   v-bind:属性名="Vue中的变量"
	简写语法:         :属性名='Vue中的变量'

列表循环

* 在vue中使用v-for实现数组的遍历,格式如下:
* v-for="(item,index) in items"
    items:要遍历的List
    item: 每次遍历得到的临时变量
    index:每次遍历的索引,从0开始计数(可省略)

代码

<!--
    * 在vue中使用v-for实现数组的遍历,格式如下:
    * v-for="(item,index) in items"
        items:要遍历的List
        item: 每次遍历得到的临时变量
        index:每次遍历的索引,从0开始计数

    要循环哪一部分,就把v-for写在哪一部分上
-->
<div id="app">
    <ul>
        <li v-for="(user,index) in users">{{index}}--{{user.id}}--{{user.name}}--{{user.address}}</li>
    </ul>
</div>

条件判断

* 语法:
	v-if="布尔表达式"
	v-else-if="布尔表达式"
	v-else
* 注意:
	v-else元素必须紧跟在带v-if或者v-else-if元素的后面,否则它将不会被识别
	v-if还可以和v-for联合使用,当二者出现在一起时,会先遍历再判断条件

事件处理

* 事件绑定
	1) 标准语法   v-on:事件名="js片段或函数名"   如果不想页面爆红,需要单独引入名称空间
	2) 简化语法   @事件名="js片段或函数名"       推荐使用

异步交互

axios使用

Vue并没有直接处理ajax的组件,需要使用第三方插件实现。Vue官网推荐使用 Axios 插件实现ajax功能。

// 执行get请求
axios.get('/url?name=admin&password=123').then(resp=>{
	console.log(resp.data);
})


// 执行get请求参数比较多的时候
axios.get('/url',{
    params:{
		name: 'admin',
		password: '123'
    }
}).then(resp=>{
	console.log(resp.data);
})


//执行post请求
axios.post('/url', {
    name: 'admin',
    password: '123'
}).then(resp=>{
    console.log(resp.data);
})

页面加载完成

created方法用于定义页面加载完毕之后需要执行的事情

const app = new Vue({
	created() {
		console.log("页面加载完毕了......");
	}
});

总结

<!--Vue对象模板-->
<script>
    let app = new Vue({
        el: "#app",
        data: {}, -- 别写 date
        methods: {}, -- 别写 method
        created() {} -- 别写 create     create:{}    别将这个方法写到methods里面
    });
</script>

1. 单方向赋值(数据-->页面)
	html文本: {{变量}}
	html属性: <span :属性="变量"> </span>

2. 双向绑定(数据<-->页面)
	<input type="text" v-model="变量"></input>

3. 遍历循环
	<li v-for="(item,index) in  items"></li>

4. 判断
	<span v-if=""></span>
	<span v-else-if=""></span>
	<span v-else></span>

5. 事件绑定
	<a @事件名="函数()"></a>

6. ajax请求
	get请求
        axios.get('/url?name=admin&password=123').then(resp=>{
            console.log(resp.data); -- resp.data()    resp.date
        })
	post请求
        axios.post('/url', {
            name: 'admin',
            password: '123'
        }).then(resp=>{
            console.log(resp.data);
        })

实例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
   <!-- 指定字符集 -->
   <meta charset="utf-8">
   <title>学生列表</title>
   <style type="text/css">
        td, th {
            text-align: center;
        }
   </style>
   <link href="./css/bootstrap.min.css" rel="stylesheet">
   <script src="./js/jquery-2.1.0.min.js"></script>
   <script src="./js/bootstrap.min.js"></script>
   <script src="./js/vue-2.6.12.js"></script>
   <script src="./js/axios-0.20.0.js"></script>
</head>
<body>
<div class="container" id="app">
   <!--列表-->
   <div class="row">
      <h3 style="text-align: center">学生列表</h3>
      <div class="col-lg-3"></div>
      <div class="col-lg-6">
         <table border="1" class="table table-bordered table-hover">
            <tr class="success" style="text-align: center">
               <th>学号</th>
               <th>姓名</th>
               <th>生日</th>
               <th>地址</th>
               <th>操作</th>
            </tr>
            <tr v-for="(student,index) in studentList">
               <td>{{student.id}}</td>
               <td>{{student.name}}</td>
               <td>{{student.birthday}}</td>
               <td>{{student.address}}</td>
               <td>
                  <a class="btn btn-default btn-sm" data-toggle="modal" data-target="#updateModal" @click="findById(student.id)">修改</a>
                  <a class="btn btn-default btn-sm" href="" @click="deleteById(student.id)">删除</a>
               </td>
            </tr>

            <tr>
               <td colspan="9" align="center">
                  <a class="btn btn-primary" data-toggle="modal" data-target="#addModal" >添加学生</a>
               </td>
            </tr>
         </table>
      </div>
      <div class="col-lg-3"></div>
   </div>

   <!-- 新增 -->
   <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="addModalLabel">
      <div class="modal-dialog" role="document">
         <div class="modal-content">
            <div class="modal-header">
               <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                     aria-hidden="true">&times;</span></button>
               <h4 class="modal-title" id="addModalLabel">新增</h4>
            </div>
            <div class="modal-body">
               <div class="form-group">
                  <label>学号:</label>
                  <input type="text" class="form-control" name="id" placeholder="请输入学号" v-model="student.id">
               </div>
               <div class="form-group">
                  <label>姓名:</label>
                  <input type="text" class="form-control" name="name" placeholder="请输入姓名" v-model="student.name">
               </div>
               <div class="form-group">
                  <label>生日:</label>
                  <input type="text" class="form-control" name="birthday" placeholder="请输入生日" v-model="student.birthday">
               </div>
               <div class="form-group">
                  <label>地址:</label>
                  <input type="text" class="form-control" name="address" placeholder="请输入地址" v-model="student.address">
               </div>
            </div>
            <div class="modal-footer">
               <button type="button" class="btn btn-primary" @click="addStudent">新增</button>
            </div>
         </div>
      </div>
   </div>

   <!-- 修改 -->
   <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel">
      <div class="modal-dialog" role="document">
         <div class="modal-content">
            <div class="modal-header">
               <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                     aria-hidden="true">&times;</span></button>
               <h4 class="modal-title" id="updateModalLabel">修改</h4>
            </div>
            <div class="modal-body">
               <div class="form-group">
                  <label>学号:</label>
                  <input type="text" class="form-control" name="id" disabled v-model="studentUpdate.id">
               </div>
               <div class="form-group">
                  <label>姓名:</label>
                  <input type="text" class="form-control" name="name" placeholder="请输入学号" v-model="studentUpdate.name">
               </div>
               <div class="form-group">
                  <label>生日:</label>
                  <input type="text" class="form-control" name="birthday" placeholder="请输入姓名" v-model="studentUpdate.birthday">
               </div>
               <div class="form-group">
                  <label>地址:</label>
                  <input type="text" class="form-control" name="address" placeholder="请输入地址" v-model="studentUpdate.address">
               </div>
            </div>
            <div class="modal-footer">
               <button type="button" class="btn btn-primary" @click="updateStudent">修改</button>
            </div>
         </div>
      </div>
   </div>
</div>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            studentList:[],
            student: {
                id: "",
                name: "",
                birthday: "",
                address: ""
            },
           studentUpdate: {
                id: "",
                name: "",
                birthday: "",
                address: ""
            }
        },
        methods:{
            //删除学生数据
           deleteById(id){
             axios.get("/studentServlet?action=delete&id="+id).then(resp=>{

             })
           },
            //修改学生数据
           updateStudent(){
               axios.post("/studentServlet?action=update",this.studentUpdate).then(resp=>{
                   if (resp.data=="OK"){
                       this.studentUpdate={};
                       $("#updateModal").modal('hide');
                       this.findList();
                   }
               })
           },
           //得到学生数据
           findById(id){
            axios.get("/studentServlet?action=findById&id="+id).then(resp=>{
                    this.studentUpdate = resp.data;
            })
           },
            //添加学生
            addStudent(){
              axios.post("/studentServlet?action=add",this.student).then(resp=>{
               if (resp.data=="OK"){
                   this.student={};
                        $("#addModal").modal('hide');
                   this.findList();
               }
              })
            },
            //查询全部
            findList(){
                axios.get("/studentServlet?action=list").then(resp =>{
                    this.studentList = resp.data;
                    console.log(this.studentList);
                })
            }
        },
        created(){
            this.findList();
        }
    });
</script>

</body>
</html>

Element

介绍

  • Element是饿了么公司前端开发团队提供的一套基于Vue的网站组件库,作用是帮助开发人员快速搭建网站

  • Element提供了大量的写好的页面组件,例如按钮、图片、表格、导航条、表单等等,开发人员可以直接复制使用

  • Element官网:Element - The world's most popular Vue UI framework

 <script src="./js/vue.js"></script>
    <script src="./element-ui/lib/index.js"></script>
    <link rel="stylesheet" href="./element-ui/lib/theme-chalk/index.css">

入门

按钮

<!--3. 从官网中找到自己想要的效果,然后把代码复制到这个位置-->
    <!--
        el-button: 表示按钮
        type="primary"  区分颜色
    -->
    script>
    <el-button type="warning" round>警告按钮</el-button>
    //2. 构建Vue对象
    let app = new Vue({
        el: "#app",
        data: {}
    })
</script>

栅格布局

    <!--
        <el-row>   一行
            :gutter="20"  列之间的间隔
        <el-col>    一列
            :span=24      栅格布局会将一行划分为24分, 我们可以使用span声明当前列占了多少份
    -->
    <el-row>
        <el-col :span="6">
            <div class="grid-content bg-purple-dark"></div>
        </el-col>
    </el-row>
    
    <script>
    let app = new Vue({
        el: '#app'
    })
</script>

容器布局

表格组件

<div id="app">

    <!--
        el-table  表格
            data  当前表格要赋值的数据
            selection-change 当点击复选框的时候会触发这个时间
        el-table-column 表格中得每一列
            label 当前列名
            prop 表示的就是当前列要渲染数据中得哪一个属性
    -->
    <el-table
            :data="tableData"
            style="width: 100%"
            @selection-change="handleSelectionChange">
        <el-table-column
                type="selection"
                width="55">
        </el-table-column>
        <el-table-column prop="date" label="日期" width="180"></el-table-column>
        <el-table-column prop="name" label="姓名" width="180"></el-table-column>
        <el-table-column prop="address" label="地址"></el-table-column>
        <el-table-column label="操作">
            <template slot-scope="scope">
                <el-button
                        type="warning"
                        size="mini"
                        @click="handleEdit(scope.$index, scope.row)">编辑
                </el-button>
                <el-button
                        size="mini"
                        type="danger"
                        @click="handleDelete(scope.$index, scope.row)">删除
                </el-button>
            </template>
        </el-table-column>
    </el-table>
</div>
 <script>
    new Vue({
        el: '#app',
        data: {
            multipleSelection: [],//用于收集被选中的行
            tableData: [
                {
                    date: '2016-05-02',
                    name: '王小虎',
                    address: '上海市普陀区金沙江路 1518 弄'
                },
                {
                    date: '2016-05-04',
                    name: '王小虎',
                    address: '上海市普陀区金沙江路 1517 弄'
                },
                {
                    date: '2016-05-01',
                    name: '王小虎',
                    address: '上海市普陀区金沙江路 1519 弄'
                },
                {
                    date: '2016-05-03',
                    name: '王小虎',
                    address: '上海市普陀区金沙江路 1516 弄'
                }
            ]
        },
        methods: {
            //index 表示的就是索引
            //row 表示当前按钮所在行对象数据
            handleEdit(index, row) {
                console.log(index, row);
            },

            //点击删除的时候触发
            handleDelete(index, row) {
                console.log(index, row);
            },

            //点击复选框的时候触发
            handleSelectionChange(val) {
                this.multipleSelection = val;
                console.log(this.multipleSelection);
            }
        }
    })
</script>

表单组件

<body>
<div id="app">
    <!--
        el-form 表单
            ref="form"  当前表单的标识,类似于id
            :model="form"  给当前表单绑定数据
        el-form-item  表单项
            label="活动名称" 名称
        el-input 文本框
        el-select 下拉框
        el-date-picker 日期
        el-time-picker 时间
        el-switch   开关
        el-checkbox-group  复选框组(v-model写在这个标签上)
            el-checkbox 一个复选框
        el-radio-group   单选框组(v-model写在这个标签上)
            el-radio  一个单选框
        el-button 按钮
    -->
    <el-form ref="form" :model="form" label-width="80px">
        <el-form-item label="活动名称">
            <el-input v-model="form.name"></el-input>
        </el-form-item>
        <el-form-item label="活动区域">
            <el-select v-model="form.region" placeholder="请选择活动区域">
                <el-option label="区域一" value="shanghai"></el-option>
                <el-option label="区域二" value="beijing"></el-option>
            </el-select>
        </el-form-item>
        <el-form-item label="活动时间">
            <el-col :span="11">
                <el-date-picker type="date" placeholder="选择日期" v-model="form.date1"
                                style="width: 100%;"></el-date-picker>
            </el-col>
            <el-col class="line" :span="2">-</el-col>
            <el-col :span="11">
                <el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
            </el-col>
        </el-form-item>
        <el-form-item label="即时配送">
            <el-switch v-model="form.delivery"></el-switch>
        </el-form-item>
        <el-form-item label="活动性质">
            <el-checkbox-group v-model="form.type">
                <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
                <el-checkbox label="地推活动" name="type"></el-checkbox>
                <el-checkbox label="线下主题活动" name="type"></el-checkbox>
                <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
            </el-checkbox-group>
        </el-form-item>
        <el-form-item label="特殊资源">
            <el-radio-group v-model="form.resource">
                <el-radio label="线上品牌商赞助"></el-radio>
                <el-radio label="线下场地免费"></el-radio>
            </el-radio-group>
        </el-form-item>
        <el-form-item label="活动形式">
            <el-input type="textarea" v-model="form.desc"></el-input>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="onSubmit">立即创建</el-button>
            <el-button>取消</el-button>
        </el-form-item>
    </el-form>
</div>
<script>
    new Vue({
        el: '#app',
        data: {
            form: {
                name: '',
                region: '',
                date1: '',
                date2: '',
                delivery: false,
                type: [],
                resource: '',
                desc: ''
            }
        },
        methods: {
            onSubmit() {
                console.log('submit!');
            }
        }
    })
</script>

对话框组件

<div id="app">

    <!--
        一个按钮
        @click="dialogFormVisible = true"  当点击按钮的时候 就会把dialogFormVisible置为true
    -->
    <el-button type="text" @click="dialogFormVisible = true">打开嵌套表单的 Dialog</el-button>

    <!--
        el-dialog 对话框
             title="收货地址"   对话框标题
            :visible.sync="dialogFormVisible"  此值用于控制对话框是否显示
    -->
    <el-dialog title="收货地址" :visible.sync="dialogFormVisible">
        <!--一个表单-->
        <el-form :model="form">
            <el-form-item label="活动名称" :label-width="formLabelWidth">
                <el-input v-model="form.name" autocomplete="off"></el-input>
            </el-form-item>
            <el-form-item label="活动区域" :label-width="formLabelWidth">
                <el-select v-model="form.region" placeholder="请选择活动区域">
                    <el-option label="区域一" value="shanghai"></el-option>
                    <el-option label="区域二" value="beijing"></el-option>
                </el-select>
            </el-form-item>
        </el-form>

        <!--下面两个按钮-->
        <div slot="footer" class="dialog-footer">
            <el-button @click="dialogFormVisible = false">取 消</el-button>
            <el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
        </div>
    </el-dialog>
</div>
<script>
    new Vue({
        el: '#app',
        data:{
            dialogFormVisible: false, //变量,控制对话框是否显示
            form: {
                name: '',
                region: '',
                date1: '',
                date2: '',
                delivery: false,
                type: [],
                resource: '',
                desc: ''
            },
            formLabelWidth: '120px'
        }
    })
</script>

分页

分页类型

逻辑分页: 一次将数据表中的所有数据查询回来,然后通过java代码在内存中完成分页, 只适合小数据量情况下

物理分页: 通过sql语句精确提取每页数据, 适合所有情况

分页函数

在mysql中使用limit关键字可以完成数据的分页

select * from student limit (当前页码-1)*每页条数,每页条数

分页插件

PageHelper 是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流与常用的数据库,

他可以帮助程序员构建PageInfo对象,内部实现了分页逻辑,程序员可以直接使用。

官网:MyBatis 分页插件 PageHelper

添加依赖

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.3</version>
        </dependency>

添加配置

在mybatis的主配置文件的environments上方加入下面配置

注意先后顺序

    <!--打印sql-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="autoRuntimeDialect" value="true"/>
        </plugin>
    </plugins>

分页代码

public PageInfo<Student> findByPage(Integer pageNum, Integer pageSize) {
        //0. 准备Mapper
        SqlSession sqlSession = StudentMapperUtil.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        //1. 开启分页
        PageHelper.startPage(pageNum, pageSize);

        //2. 执行查询
        List<Student> list = mapper.findAll();

        //3. 构建返回的pageInfo
        PageInfo<Student> pageInfo = new PageInfo<>(list);

        //5. 关闭sqlSession
        StudentMapperUtil.commitAndClose(sqlSession);
        return pageInfo;
    }
}

插件原理

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值