Bootstrap

Ajax + JQuery 实战开发

Ajax + JQuery 实战开发

准备工作:

修改后台表格页面,bootstrap.css

静态资源

在springboot项目中,static是静态资源目录。这个目录在访问时候和在引入的时候都不需要指定。如果你未来的程序调用和执行过程中,如果发现访问不了。或者引入不到。只能说明一个点:

  • 要么名字写错,要么引入路径不对

  • 更多的可能是:没有编译到target/classes

bootstrap

全局 CSS 样式 · Bootstrap v3 中文文档 | Bootstrap 中文网

Get请求查询 - 非实体参数注入

1: 查询

   /**
     * 用户分页查询
     * 接口路径:/admin/user/load
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("/user/load")
    public IPage<User> findUserPages(int pageNo,int pageSize){
        // 1: 定义分页
        Page<User> page = new Page(pageNo,pageSize);
        // 2:设置查询条件
        LambdaQueryWrapper<User> lambdaQueryWrapper =
        new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getIsDelete,0);
        lambdaQueryWrapper.orderByDesc(User::getCreateTime);
        // 3: 查询分页
        return userService.page(page,lambdaQueryWrapper);
    }
​
  • 请求方式:GET

  • 请求地址:http://localhost:8699/admin/user/load

  • 请求参数:

    int pageNo
    int pageSize

    注意:如果在什么都不指定的情况下,参数默认是:必填的

    因为上面的请求方式是:get请求,根据get请求规则和规范参数是放入在:请求地址后面用以?name=zzz&age=11&name=2322 格式进行显示的传输和定义。

    也就就说。你要请求上面的接口:你必须要增加pageNo和pageSize这两个参数可以可以访问,否则拒绝。

    解决方案:

    • 必填

    • 可以使用springmvc的@RequestParams机制,填写默认值。这样在第一次调用的过程中,如果你不填写我就用默认值填充。

       @GetMapping("/user/load")
      public IPage<User> findUserPages(
          @RequestParam(name="pageNo",defaultValue = "1") int pageNo,
                                          @RequestParam(name="pageSize",defaultValue = "10") int pageSize
      ){
            

  • postman测试

        运行结果
  • {
        "records": [
            {
                "id": 459,
                "nickname": "赵彦",
                "username": "赵彦",
                "age": 24,
                "sign": "爱你所爱 行你所行 听从你心 无问东西",
                "sex": 0,
                "views": 0,
                "job": "Java开发",
                "jobyear": "2",
                "address": "济南",
                "country": "中国",
                "province": null,
                "city": null,
                "telephone": "19653166182",
                "weixincode": "19653166182",
                "education": null,
                "birthday": "",
                "avatar": "/avatar/2.jpg",
                "bgimg": null,
                "vip": 2,
                "vipTime": null,
                "cron": 50,
                "studydays": 1,
                "isDelete": 0,
                "forbbiden": 1,
                "qqcode": "1810660001",
                "code": "0",
                "role": "normal",
                "password": "850e96fa21249a4ba972a531d9ae1f37",
                "openid": null,
                "unionid": null,
                "fans": 0,
                "gznums": 0,
                "bloglink": null,
                "giteelink": null,
                "bilibililink": null,
                "createTime": "2022-04-08T09:43:28.000+00:00",
                "updateTime": "2022-04-08T09:43:28.000+00:00"
            },
            {
                "id": 458,
                "nickname": "赵赟",
                "username": "赵赟",
                "age": 24,
                "sign": "爱你所爱 行你所行 听从你心 无问东西",
                "sex": 0,
                "views": 0,
                "job": "Java开发",
                "jobyear": "0",
                "address": "杭州",
                "country": "中国",
                "province": null,
                "city": null,
                "telephone": "13116767698",
                "weixincode": "zy1029495988",
                "education": null,
                "birthday": "",
                "avatar": "/avatar/3.jpg",
                "bgimg": null,
                "vip": 2,
                "vipTime": null,
                "cron": 50,
                "studydays": 1,
                "isDelete": 0,
                "forbbiden": 1,
                "qqcode": "1029495988",
                "code": "0",
                "role": "normal",
                "password": "d0a3abf693af15e4b71c29b9a1426af8",
                "openid": null,
                "unionid": null,
                "fans": 0,
                "gznums": 0,
                "bloglink": null,
                "giteelink": null,
                "bilibililink": null,
                "createTime": "2022-03-07T05:39:26.000+00:00",
                "updateTime": "2022-03-07T05:39:26.000+00:00"
            }
        ],
        "total": 441,
        "size": 2,
        "current": 1,
        "orders": [],
        "optimizeCountSql": true,
        "searchCount": true,
        "countId": null,
        "maxLimit": null,
        "pages": 221
    }

Get请求查询 - 实体对象参数注入

Springmvc本身已经对httpserletRequest和bean的参数的注入已经支持了。但是你必须要遵循一些条件:

  • 就是参数的名字必须和bean的属性的名字要一致

  • 必须生成getter/setter方法

bean的部分

package com.pug.vo;
​
import lombok.Data;
​

@Data
public class UserVo implements java.io.Serializable{
    private Integer pageNo = 1;
    private Integer pageSize = 10;
    private String keyword;
}
​

请求部分

  $.get("/admin/user/load?pageNo="+that.pageNo+"&keyword=12&pageSize="+that.pageSize)

注意:pageNo 和 pageSize 和 keyword必须和Uservo的属性名要一摸一样,注入不进去。

测试

Form表单数据的方式

你必须要知道是事情?

  • 在开发中,其实不论用get还是post,form都可以完成数据的传输和注入。只不过有一个差别:get请求的参数是暴露url地址的后面。而post请求是通过请求体进行传输的。

  • 所以,get请求的url和参数,每隔浏览器都会限制长度,比如:google 8k~10K .如果超过自动截取丢失。所以get请求不是说做不到数据的传递和注入,是因为长度有限制。post目前可以支持2M。而且不会暴露在url地址后面是通过请求body传输的。

  • 也就是告诉你一个道理。在开发中,不要总是纠结于提交表单只能post的这个谬论。

  • 但是为安全起见,确实在开发中,我们只要做注册或者添加数据时候都只考虑post。

你必须要知道是事情?-前端部分

  • label 是form表单的关系户标签,只要form元素(input,radio,select.checkbox,textarea)被label包裹的话,文本部分和元素不论你点击元素还是点文档都自动获取焦点。这也为什么说你经常在form表单定义中经常看到label标签的原因。

  • button、submit它们都自动提交form能力

  • form如果不指定method请求方式就是get请求

  • 如果你选择用异步去提交了。button和submit这个默认能力你就要去卸载掉。button和submit只用ajax去处理,不用form去处理。

Jquery的异步总结

  • 不论你是get还是post在后端,不论你是对象还是单个参数启动都是可以进入注入和获取的。

  • JQuery操作的dom节点,很多时候我们都是先要找到元素,才进行操作(事件处理,加样式,添加内容等)

Vue3+ Axios处理异步请求

vue和jquery的区别

  • vue去dom化

  • jquery围绕dom

Axios的认识

axios也是对XMLHttpRequest的封装,只不过它通过es6的语法Promise(承诺)来进行封装。

  • 从浏览器中创建 XMLHttpRequests

  • 从 node.js 创建 http 请求

  • 支持 Promise API

  • 拦截请求和响应

  • 转换请求数据和响应数据

  • 取消请求 (timeout 10s)

  • 自动转换 JSON 数据

  • 客户端支持防御 XSRF

如何使用Axios

  • 使用自带

    • Promise

      axios#request(config)
      axios#get(url[, config])
      axios#delete(url[, config])
      axios#head(url[, config])
      axios#options(url[, config])
      axios#post(url[, data[, config]])
      axios#put(url[, data[, config]])
      axios#patch(url[, data[, config]])

      常用就是: get 和 post

  • 自己创建axios对象

    • 什么情况会去创建呢?未来如果你异步请求需要有拦截器机制或者通用处理。肯定自己去创建会更好一些。

    • request.js

      const request = axios.create({
          baseURL: 'https://api.example.com',
          timeout: 1000,
          headers: {'X-Custom-Header': 'foobar'}
      });
      
      
      // 添加请求拦截器
      request.interceptors.request.use(function (config) {
          var token = cache.getToken();
          // 在发送请求之前做些什么
          config.headers = {
                              'X-Requested-With': 'XMLHttpRequest',
                              'token':token
                          };
          return config;
      }, function (error) {
          // 对请求错误做些什么
          return Promise.reject(error);
      });
      
      // 添加响应拦截器
      request.interceptors.response.use(function (response) {
          if(res.data.code == 500){
              alert("服务器错误....")
              return;
          }
          // 对响应数据做点什么
          return response.data;
      }, function (error) {
          // 对响应错误做点什么
          return Promise.reject(error);
      });
      
      export default request;
      index.vue
      <template>
      	<div v-for="(user,user) in users">{{user.username}}</div>
      </template>
      
      <scrcipt setup>
      import request from '@/utils/request.js'
      import axios from 'axios'
      
      var users = reactive([]);
      onMounted(()=>{
      
      	request.get("/admin/user/list").then(res=>{
              users = res.data;
          })    
      });
      
      
      </script>

Axios 的请求配置

 

axios.post(“http://localhost:8699/admin/”)

{
   // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // default

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  transformRequest: [function (data, headers) {
    // 对 data 进行任意转换处理
    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对 data 进行任意转换处理
    return data;
  }],

  // `headers` 是即将被发送的自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },

   // `paramsSerializer` 是一个负责 `params` 序列化的函数
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },

  // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,

   // `withCredentials` 表示跨域请求时是否需要使用凭证
  withCredentials: false, // default

  // `adapter` 允许自定义处理请求,以使测试更轻松
  // 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
  adapter: function (config) {
    /* ... */
  },

 // `auth` 表示应该使用 HTTP 基础验证,并提供凭据
  // 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

   // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  responseType: 'json', // default
      

  // `responseEncoding` indicates encoding to use for decoding responses
  // Note: Ignored for `responseType` of 'stream' or client-side requests
  responseEncoding: 'utf8', // default

   // `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

   // `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // Do whatever you want with the native progress event
  },

  // `onDownloadProgress` 允许为下载处理进度事件
  onDownloadProgress: function (progressEvent) {
    // 对原生进度事件的处理
  },

   // `maxContentLength` 定义允许的响应内容的最大尺寸
  maxContentLength: 2000,

  // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  validateStatus: function (status) {
    return status >= 200 && status < 300; // default
  },

  // `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
  // 如果设置为0,将不会 follow 任何重定向
  maxRedirects: 5, // default

  // `socketPath` defines a UNIX Socket to be used in node.js.
  // e.g. '/var/run/docker.sock' to send requests to the docker daemon.
  // Only either `socketPath` or `proxy` can be specified.
  // If both are specified, `socketPath` is used.
  socketPath: null, // default

  // `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
  // `keepAlive` 默认没有启用
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // 'proxy' 定义代理服务器的主机名称和端口
  // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
  // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
  proxy: {
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // `cancelToken` 指定用于取消请求的 cancel token
  // (查看后面的 Cancellation 这节了解更多)
  cancelToken: new CancelToken(function (cancel) {
  })
}

Axios 响应结构

{
  // `data` 由服务器提供的响应
  data: {
      code:200,
      message:"success",
      data:{}
 
  },

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 服务器响应的头
  headers: {},

   // `config` 是为请求提供的配置信息
  config: {},
 // 'request'
  // `request` is the request that generated this response
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}
}

Axios的完整写法如下

  • axios(config)

// 发送 POST 请求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});



// 获取远端图片
axios({
  method:'get',
  url:'http://bit.ly/2mTM3nY',
  responseType:'stream'
})
  .then(function(response) {
  response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
  • axios(url[, config])

// 发送 GET 请求(默认的方法)
axios('/user/12345');

axios变体

axios#request(config)
axios#get(url[, config])
axios#delete(url[, config])
axios#head(url[, config])
axios#options(url[, config])
axios#post(url[, data[, config]])
axios#put(url[, data[, config]])
axios#patch(url[, data[, config]]

Axios.propertype.get = function(url,params){
	return axios({method:'get',url:url,params});
}

Axios.propertype.post = function(url,data){
	return axios({method:'post',url:url,data});
}

["get","post","delete","patch"].forEach(m=>{
    Axios.propertype[m] = function(url,data){
		return axios({method:m,url:url,data});
	}
})



var axios = new Axios();
var request = new Axios();
var xiyuan = new Axios();

Axios的get请求传递参数的两种方式

1:直接拼接

// 记住?记得加哦!!!
var params = "?
pageNo="+this.pageNo+"&pageSize="+this.pageSize+"&keyword="+this.keyword;
request.get("/admin/v/user/load"+params).then((res)=>{
    this.userList = res.data.records;
    this.total = res.data.total;
    this.pages = res.data.pages;
})

2:使用params

request.get("/admin/v/user/load",{
    params:{
        pageNo:this.pageNo,
        pageSize:this.pageSize,
        keyword:this.keyword
    }
}).then((res)=>{
    this.userList = res.data.records;
    this.total = res.data.total;
    this.pages = res.data.pages;
})

## 或者
var params = {
    pageNo:this.pageNo,
    pageSize:this.pageSize,
    keyword:this.keyword
};
request.get("/admin/v/user/load",{params:params}).then((res)=>{
    this.userList = res.data.records;
    this.total = res.data.total;
    this.pages = res.data.pages;
})

请求的过程:

服务端代码:

对象写法:

    /**
     * 用户分页查询
     * 接口路径:/admin/user/load
     *
     * @param userVo
     * @param userVo
     * @return
     */
    @GetMapping("/v/user/load")
    public IPage<UserBo> findUserPages(UserVo userVo, HttpServletRequest request, HttpServletResponse response) {

        System.out.println(request.getHeader("token"));
        System.out.println(request.getHeader("X-Custom-Header"));
        // 1: 定义分页
        Page<User> page = new Page(userVo.getPageNo(), userVo.getPageSize());
        // 2:设置查询条件
        LambdaQueryWrapper<User> lambdaQueryWrapper =
                new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(!StringUtils.isEmpty(userVo.getKeyword()), User::getNickname, userVo.getKeyword());
        lambdaQueryWrapper.eq(User::getIsDelete, 0);
        lambdaQueryWrapper.orderByDesc(User::getCreateTime);
        // 3: 查询分页
        Page<User> page1 = userService.page(page, lambdaQueryWrapper);
        List<User> records = page1.getRecords();

        // 4 : 返回的数据
        Page<UserBo> page2 = new Page<>();
        List<UserBo> userBoList = records.stream().map(user -> {
            UserBo userBo = new UserBo();
            BeanUtils.copyProperties(user, userBo);
            return userBo;
        }).collect(Collectors.toList());

        page2.setRecords(userBoList);
        page2.setTotal(page.getTotal());
        page2.setSize(page.getSize());
        page2.setPages(page.getPages());
        page2.setCurrent(page.getCurrent());

        response.setHeader("token","00000000");

        return page2;
    }

非对象写法:

@GetMapping("/v/user/load")
    public IPage<UserBo> findUserPages(Integer pageNo , Integer pageSize, String keyword,
                                       HttpServletRequest request, HttpServletResponse response) {
        System.out.println(request.getHeader("token"));
        System.out.println(request.getHeader("X-Custom-Header"));

        UserVo userVo = new UserVo();
        userVo.setKeyword(keyword);
        userVo.setPageNo(pageNo);
        userVo.setPageSize(pageSize);
        // 1: 定义分页
        Page<User> page = new Page(userVo.getPageNo(), userVo.getPageSize());
        // 2:设置查询条件
        LambdaQueryWrapper<User> lambdaQueryWrapper =
                new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(!StringUtils.isEmpty(userVo.getKeyword()), User::getNickname, userVo.getKeyword());
        lambdaQueryWrapper.eq(User::getIsDelete, 0);
        lambdaQueryWrapper.orderByDesc(User::getCreateTime);
        // 3: 查询分页
        Page<User> page1 = userService.page(page, lambdaQueryWrapper);
        List<User> records = page1.getRecords();

        // 4 : 返回的数据
        Page<UserBo> page2 = new Page<>();
        List<UserBo> userBoList = records.stream().map(user -> {
            UserBo userBo = new UserBo();
            BeanUtils.copyProperties(user, userBo);
            return userBo;
        }).collect(Collectors.toList());

        page2.setRecords(userBoList);
        page2.setTotal(page.getTotal());
        page2.setSize(page.getSize());
        page2.setPages(page.getPages());
        page2.setCurrent(page.getCurrent());

        response.setHeader("token","00000000");

        return page2;
    }

Axios的Post请求的唯一方式

1: jquery的post传递参数

var params = this.user;
$.post("/admin/v/user/save",params);

所以在后台的时候,我们不论是单个定义还是对象对应,都可以注入参数对对应的属性中。也不限制请求方式、

2:axios的post传递参数

var params = this.user;
request.post("user/save",params).then(res=>{
    console.log("服务器返回的数据是:",res)
    alert("注册成功")
}).catch(err=>{
    console.log(err);
})

服务端代码如下:

@PostMapping("/v/user/save")
public String findUserPages(@RequestBody  UserRegVo userRegVo) {
    User user = new User();
    BeanUtils.copyProperties(userRegVo, user);
    user.setForbbiden(1);
    user.setIsDelete(0);
    return userService.saveOrUpdate(user) ? "success" : "fail";
}
;