Java体系知识之Echarts&跨域访问&Vue脚手架

366 阅读4分钟

Java体系知识之Echarts&跨域访问&Vue脚手架

 (1)Echarts图表工具
 (2)跨域访问
 (3)Vue 脚手架

1 Echarts

1.1 技术简介

 (1)Apache ECharts
 (2)一个基于 JavaScript 的开源可视化图表库
 (3)使用步骤:
     A.引入echarts.js文件
     B.创建一个指定了宽高的容器
     C.根据图表的配置项和数据以图表的形式呈现数据
         C1.基于准备好的dom,初始化echarts实例
         C2.指定图表的配置项和数据
         C3.使用刚指定的配置项和数据显示图表

1.2 案例

 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="utf-8">
         <title></title>
         <!-- 1.引入echarts文件 -->
         <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.3.3/echarts.js"></script>
 ​
     </head>
     <body>
         <!-- 2.创建一个指定了宽高的容器 -->
         <div id="main" style="width: 600px;height:400px;"></div>
     </body>
     <script>
         /* 
             3.呈现图表
          */
         // 3.1基于准备好的dom,初始化echarts实例
         var myChart = echarts.init(document.getElementById('main'));
 ​
         // 3.2指定图表的配置项和数据
         var option = {
             xAxis: {
                 type: 'category',
                 data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
             },
             yAxis: {
                 type: 'value'
             },
             series: [{
                 data: [150, 230, 224, 218, 135, 147, 260],
                 type: 'line'
             }]
             /* title: {
                 text: 'ECharts 入门示例'
             },
             tooltip: {},
             legend: {
                 data: ['销量']
             },
             xAxis: {
             data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
             },
             yAxis: {},
             series: [{
                 name: '销量',
                 type: 'bar',
                 data: [5, 20, 36, 10, 10, 20]
             }] */
         };
 ​
         // 3.3使用刚指定的配置项和数据显示图表
         myChart.setOption(option);
     </script>
 ​
 </html>
 ​

2 跨域访问(重点)

2.1 错误信息

 Access to XMLHttpRequest at 'http://localhost:8080/area' from origin 'http://127.0.0.1:8848' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 2 area.html:106 o

2.2 跨域访问

 (1)Cookie:
     A.HTTP协议:无状态协议
     B.客户端和服务端,服务端只关心请求   
     C.如何让服务端知道该客户端已经不是第一次访问它了,可以使用Cookie
     D.数据安全考虑:
         浏览器基于Cookie同源限制
         D1.不涉及到跨域请求时,Cookie会随着请求自动发送到服务器端,用于验证自己身份
         D2.涉及到跨域请求时,默认不会在请求中携带Cookie数据
     同源:
         http://localhost:8080/具体资源
         对于协议|域名|端口,若两个页面有一个值不一样,就认为是不同源
         http://localhost:8080
         http://localhost:8081
 (2)同源政策越来越严格:
     浏览器:使用Ajax技术时,只能向自己的服务器发请求
 (3)CORS:
     Cross-Origin Resource Sharing  跨域资源共享
 (4)解决:
     在服务器端设置允许哪个客户端来访问它
     跨域请求:
         // 允许跨域的主机地址,一般写具体的客户端的主机地址,比如http://127.0.0.1:8848
         resp.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:8848");
         // 允许跨域的请求方法,GET|POST...,也可以直接写*
         resp.setHeader("Access-Control-Allow-Methods","*");
         // 重新域检验跨域的缓存时间(s)
         resp.setHeader("Access-Control-Max-Age","3600");
         // 允许跨域的请求头
         resp.setHeader("Access-Control-Allow-Headers","*");
         // 允许携带Cookie信息
         resp.setHeader("Access-Control-Allow-Credentials","true");

2.3 省市区案例-改造

2.3.1 area.html

 <!DOCTYPE html>
 <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>Title</title>
         <!--Vue.js文件-->
         <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
         <!--引入axios的库文件-->
         <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
         <!-- 引入样式 -->
         <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
         <!-- 引入组件库 -->
         <script src="https://unpkg.com/element-ui/lib/index.js"></script>
 ​
     </head>
     <body>
         <div id="root">
             <el-select v-model="proCode" placeholder="请选择" @change="getCity()">
                 <el-option v-for="pro in proList" :key="pro.areaCode" :label="pro.areaName" :value="pro.areaCode">
                 </el-option>
             </el-select>省
             <el-select v-model="cityCode" placeholder="请选择" @change="getCoun()">
                 <el-option v-for="city in cityList" :key="city.areaCode" :label="city.areaName" :value="city.areaCode">
                 </el-option>
             </el-select>市
             <el-select v-model="counCode" placeholder="请选择">
                 <el-option v-for="coun in counList" :key="coun.areaCode" :label="coun.areaName" :value="coun.areaCode">
                 </el-option>
             </el-select>区县
         </div>
     </body>
     <script>
         new Vue({
             el: "#root",
             data: {
                 /*省*/
                 proCode: '',
                 proList: [],
                 /*市*/
                 cityCode: '',
                 cityList: [],
                 /*区县*/
                 counCode: '',
                 counList: []
             },
             methods: {
                 /*加载市数据*/
                 getCity() {
                     // 将市数据恢复成请选择
                     this.cityCode = "";
                     // 把区县数据恢复成请选择
                     this.counCode = "";
                     this.counList = [];
                     // 获取省数据编号
                     var provinceCode = this.proCode;
                     console.log(provinceCode);
                     axios.get("http://localhost:8080/area?parentCode=" + provinceCode)
                         .then(resp => {
                             console.log(resp);
                             this.cityList = resp.data.returnData;
                         }).catch(error => {})
                 },
 ​
                 /*加载区县数据*/
                 getCoun() {
                     // 把区县数据恢复成请选择
                     this.counCode = "";
                     // 获取市数据编号
                     var cityCode = this.cityCode;
                     console.log(cityCode);
                     axios.get("http://localhost:8080/area?parentCode=" + cityCode)
                         .then(resp => {
                             console.log(resp);
                             this.counList = resp.data.returnData;
                         }).catch(error => {})
                 }
 ​
             },
             mounted() {
                 /*获取省数据*/
                 axios.post("http://localhost:8080/area", "parentCode=0")
                     .then(resp => {
                         console.log(resp);
                         this.proList = resp.data.returnData;
                     }).catch(error => {
                         console.log(error);
                     })
             }
         })
     </script>
 </html>

2.3.2 AreaServlet

 package com.javasm.servlet;
 ​
 import com.alibaba.fastjson.JSON;
 import com.javasm.entity.Area;
 import com.javasm.entity.CodeAndMsg;
 import com.javasm.entity.ReturnEntity;
 import com.javasm.service.AreaService;
 import com.javasm.service.impl.AreaServiceImpl;
 ​
 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;
 import java.io.PrintWriter;
 import java.util.List;
 ​
 /**
  * @author: ShangMa
  * @className: AreaServlet
  * @description: 控制层-地区
  * @date: 2022/8/24 19:30
  */
 @WebServlet("/area")
 public class AreaServlet extends HttpServlet {
     @Override
     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         // 允许跨域的主机地址,一般写具体的客户端的主机地址,比如http://127.0.0.1:8848
         resp.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:8848");
         // 允许跨域的请求方法,GET|POST...,也可以直接写*
         resp.setHeader("Access-Control-Allow-Methods","*");
         // 重新域检验跨域的缓存时间(s)
         resp.setHeader("Access-Control-Max-Age","3600");
         // 允许跨域的请求头
         resp.setHeader("Access-Control-Allow-Headers","*");
         // 允许携带Cookie信息
         resp.setHeader("Access-Control-Allow-Credentials","true");
 ​
         // 接收数据->处理请求->返回响应数据
         req.setCharacterEncoding("utf-8");
         String parentCodeStr = req.getParameter("parentCode");
         // 转型
         Integer parentCode = null;
         if (parentCodeStr != null && !"".equals(parentCodeStr)) {
             parentCode = Integer.valueOf(parentCodeStr);
         }
         // 调用业务层方法
         AreaService areaService = new AreaServiceImpl();
         List<Area> areaList = areaService.findAreaList(parentCode);
         // 写出响应数据
         resp.setContentType("application/json;charset=utf-8");
         PrintWriter writer = resp.getWriter();
         ReturnEntity re = new ReturnEntity();
         // 判断
         if (areaList.size() > 0) {
             re.setReturnCode(CodeAndMsg.DATA_SUCCESS.getReturnCode());
             re.setReturnMsg(CodeAndMsg.DATA_SUCCESS.getReturnMsg());
             re.setReturnData(areaList);
         } else {
             re.setReturnCode(CodeAndMsg.DATA_FAILURE.getReturnCode());
             re.setReturnMsg(CodeAndMsg.DATA_FAILURE.getReturnMsg());
         }
         writer.print(JSON.toJSONString(re));
         writer.flush();
         writer.close();
     }
 }

3 Vue 脚手架(重点)

3.1 技术简介

 (1)Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统
 (2)可以快速搭建完整的前端项目
 (3)有自己的服务器,涉及到跨域访问  
 (4)安装工具:
     A.Node.js
         npm 是 Node.js 标准的软件包管理器
     B.Vue脚手架
         CLI 服务是一个开发环境依赖;
         它是一个 npm 包,局部安装在每个 @vue/cli 创建的项目中;
 (5)了解:
     Babel:
         Babel 是一个工具链,主要用于在当前和旧的浏览器或环境中;
         将 ECMAScript 2015+ 代码转换为 JavaScript 向后兼容版本的代码;
     webpack:
         是一个现代 JavaScript 应用程序的静态模块打包器->module bundler;
         当 webpack 处理应用程序时,它会递归地构建一个依赖关系图;
         包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle
 (6)单页面应用
 (7)修改端口号:
     const {
         defineConfig
     } = require('@vue/cli-service')
     module.exports = defineConfig({
         transpileDependencies: true,
         /* 设置端口号 */
         devServer: {
             port: 8088, //端口
         }
     })

3.2 新增功能

 (1)创建vue文件
 (2)导入组件、配置组件

3.3 案例

3.3.1 Login.vue

 <template>
     <!-- Card卡片 -->
     <el-card class="box-card">
         <div slot="header" class="clearfix">
             <span>登录</span>
         </div>
         <!-- 
             Form表单:
                 hide-required-asterisk  是否隐藏必填字段的标签旁边的红色星号
         -->
         <el-form ref="loginForm" :model="loginForm" label-width="80px" :rules="rules" hide-required-asterisk>
             <el-form-item label="用户名" prop="userName">
                 <el-input v-model="loginForm.userName" prefix-icon="el-icon-user"></el-input>
             </el-form-item>
             <el-form-item label="密码" prop="userPwd">
                 <el-input v-model="loginForm.userPwd" show-password prefix-icon="el-icon-lock"></el-input>
             </el-form-item>
             <el-form-item>
                 <el-button type="primary" @click="submitForm('loginForm')">登录</el-button>
                 <el-button @click="resetForm('loginForm')">重置</el-button>
             </el-form-item>
         </el-form>
     </el-card>
 </template>
 ​
 <script>
     export default {
         data() {
             return {
                 loginForm: {
                     userName: '',
                     userPwd: '',
                 },
                 rules: {
                     userName: [{
                             required: true,
                             message: '请输入用户名',
                             trigger: 'blur'
                         },
                         {
                             min: 4,
                             max: 8,
                             message: '长度在 4 到 8 个字符',
                             trigger: 'blur'
                         }
                     ],
                     userPwd: [{
                             required: true,
                             message: '请输入密码',
                             trigger: 'blur'
                         },
                         {
                             min: 4,
                             max: 8,
                             message: '长度在 4 到 8 个字符',
                             trigger: 'blur'
                         }
                     ],
                 }
 ​
             }
         },
         methods: {
             submitForm(formName) {
                 this.$refs[formName].validate((valid) => {
                     console.log(valid);
                     if (valid) {
                         // alert('submit!');
                         // 向服务器端发请求  登录成功|登录失败
                         // 登录成功->进入系统主界面
                         this.$router.push('/main');
                     } else {
                         console.log('error submit!!');
                         return false;
                     }
                 });
             },
             resetForm(formName) {
                 this.$refs[formName].resetFields();
             }
         },
         mounted() {
 ​
         }
     }
 </script>
 ​
 <style>
     /* Card卡片 */
     .text {
         font-size: 14px;
     }
 ​
     .item {
         margin-bottom: 18px;
     }
 ​
     .clearfix:before,
     .clearfix:after {
         display: table;
         content: "";
     }
 ​
     .clearfix:after {
         clear: both
     }
 ​
     .box-card {
         width: 480px;
         margin: 179px auto;
     }
 </style>

3.3.2 Main.vue

<template>
	<!-- Container 布局容器 -->
	<el-container>
		<el-header>
			java教育金融系统
		</el-header>
		<el-container>
			<el-aside width="200px">
				<el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose">
					<!-- 属性绑定 -->
					<el-submenu :index="menu.menuId.toString()" v-for="menu in menuList">
						<template slot="title">
							<!-- 图标 -->
							<i :class="menu.menuIcon"></i>
							<!-- 插值语法 -->
							<span>{{menu.menuName}}</span>
						</template>
						<el-menu-item-group>
							<el-menu-item :index="sub.menuId.toString()" v-for="sub in menu.subMenu">{{sub.menuName}}
							</el-menu-item>
						</el-menu-item-group>
					</el-submenu>
				</el-menu>
			</el-aside>
			<el-main>Main</el-main>
		</el-container>
	</el-container>

</template>

<script>
	export default {
		data() {
			return {
				activeIndex2: '1',
				// 模拟数据
				menuList: [{
					"menuId": 1000,
					"menuName": "系统模块",
					"menuIcon": "el-icon-s-tools",
					"subMenu": [{
						"menuId": 1001,
						"menuName": "用户模块"
					}, {
						"menuId": 1002,
						"menuName": "菜单模块"
					}]
				}, {
					"menuId": 2000,
					"menuName": "产品模块",
					"menuIcon": "el-icon-s-goods",
					"subMenu": [{
						"menuId": 2001,
						"menuName": "产品系列模块"
					}, {
						"menuId": 2002,
						"menuName": "产品基础模块"
					}]
				}]

			}
		},
		methods: {
			handleSelect(key, keyPath) {
				console.log(key, keyPath);
			},
			handleOpen(key, keyPath) {
				console.log(key, keyPath);
			},
			handleClose(key, keyPath) {
				console.log(key, keyPath);
			},
			queryMenus() {}

		},
		mounted() {
			this.queryMenus();
		}
	}
</script>

<style>
	/* Container 布局容器 */
	.el-header,
	.el-footer {
		background-color: #B3C0D1;
		color: #333;
		text-align: center;
		line-height: 60px;
	}

	.el-aside {
		background-color: #D3DCE6;
		color: #333;
		text-align: center;
		line-height: 200px;
	}

	.el-main {
		background-color: #E9EEF3;
		color: #333;
		text-align: center;
		line-height: 160px;
	}

	body>.el-container {
		margin-bottom: 40px;
	}

	.el-container:nth-child(5) .el-aside,
	.el-container:nth-child(6) .el-aside {
		line-height: 260px;
	}

	.el-container:nth-child(7) .el-aside {
		line-height: 320px;
	}

	/* 自增样式 */
	html,
	body,
	#root,
	.el-container {
		height: 100%;
	}

	* {
		margin: 0;
		padding: 0;
	}
</style>