一、统一日志处理
1、日志
1)、配置日志级别
日志记录器(Logger)的行为是分等级的。如下表所示:
分为:OFF
、FATAL
、ERROR
、WARN
、INFO
、DEBUG
、ALL
默认情况下,SpringBoot
从控制台打印出来的日志级别只有 INFO
及以上级别,可以配置日志级别。
# 设置日志级别
logging.level.root=WARN
这种方式只能将日志打印在控制台上。
2、Logback
日志
SpringBoot
内部使用 Logback
作为日志实现的框架。
Logback
和 log4j
非常相似,如果你对 log4j
很熟悉,那对 logback
很快就会得心应手。
logback
相对于 log4
j的一些优点:https://blog.csdn.net/caisini_vc/article/details/48551287
1)、配置 logback
日志
删除 application.properties
中的日志配置
# 设置日志级别
#logging.level.root=WARN
# mybatis日志
#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
resources 中创建 logback-spring.xml
,名字是固定的,不建议改!
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设
置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值
为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认
单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查
看logback运行状态。默认值为false。 -->
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入
到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<!--日志输出在文件夹的哪个位置-->
<property name="log.path" value="D:\JAVA\log"/>
<!-- 彩色日志 -->
<!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->
<!-- magenta:洋红 -->
<!-- boldMagenta:粗红-->
<!-- cyan:青色 -->
<!-- white:白色 -->
<!-- magenta:洋红 -->
<property name="CONSOLE_LOG_PATTERN"
value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level)
|%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
<!--输出到控制台-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或
等于此级别的日志信息-->
<!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日
志,也不会被输出 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_info.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level
%logger{50} - %msg%n
</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-
dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录info级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 WARN 日志 -->
<appender name="WARN_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_warn.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level
%logger{50} - %msg%n
</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-
dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录warn级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>warn</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/log_error.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level
%logger{50} - %msg%n
</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-
dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志文件只记录ERROR级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!--
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指
定<appender>。
<logger>仅有一个name属性,
一个可选的level和一个可选的addtivity属性。
name:用来指定受此logger约束的某一个包或者具体的某一个类。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL
和 OFF,
如果未设置此属性,那么当前logger将会继承上级的级别。
-->
<!--
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想
要查看sql语句的话,有以下两种操作:
第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过
这样日志那边会出现很多其他消息
第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打
印,其他还是正常DEBUG级别:
-->
<!--开发环境:打印控制台-->
<springProfile name="dev">
<!--可以输出项目中的debug日志,包括mybatis的sql日志-->
<logger name="com.guli" level="INFO"/>
<!--
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR,
ALL 和 OFF,默认是DEBUG
可以包含零个或多个appender元素。
-->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</springProfile>
<!--生产环境:输出到文件-->
<springProfile name="pro">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
<appender-ref ref="WARN_FILE"/>
</root>
</springProfile>
</configuration>
2)、将错误日志输出到文件
GlobalExceptionHandler.java
上添加注解 @Slf4j
异常输出语句:
log.error(e.getMessage());
二、前端开发和前端开发工具
PRD(产品原型-产品经理) - PSD(视觉设计-UI工程师) - HTML/CSS/JavaScript(PC/移动端网页,实现网页端的视觉展示和交互-前端工程师)
1、下载和安装 VSCode
下载地址:https://code.visualstudio.com/
中文界面配置:
-
首先安装中文插件:Chinese (Simplified) Language Pack for Visual Studio Code
-
右下角弹出是否重启 VSCode,点击 “yes”
-
有些机器重启后如果界面没有变化,则 点击 左边栏 Manage -> CommandPaletet…【Ctrl+Shift+p】
-
在搜索框中输入“configure display language”,回车
-
打开 locale.json 文件,修改文件下的属性 “locale”:“zh-cn”
{
// 定义 VS Code 的显示语言。
// 请参阅 https://go.microsoft.com/fwlink/?LinkId=761051,了解支持的语言列表。
"locale":"zh-cn" // 更改将在重新启动 VS Code 之后生效。
}
- 重启 VSCode
2、插件安装
为方便后续开发,建议安装如下插件(红色矩形框标记的插件)。
创建项目:
vscode 本身没有新建项目的选项,所以要先创建一个空的文件夹,如 project_xxxx。
然后打开 vscode,再在 vscode 里面选择 File -> Open Folder 打开文件夹,这样才可以创建项目。
保存工作区:
打开文件夹后,选择“文件 -> 将工作区另存为…”,为工作区文件起一个名字,存储在刚才的文件夹下即可。
新建文件夹和网页:
鼠标右击工作区,然后选择对应的命令即可。
预览网页:
以文件路径方式打开网页预览
需要安装“open in browser
”插件:
文件右键 -> Open In Default Browser
以服务器方式打开网页预览:
需要安装“Live Server
”插件:
文件右键 -> Open with Live Server
设置字体大小:
左边栏 Manage -> settings -> 搜索 “font” -> Font size
开启完整的Emmet语法支持:
设置中搜索 Emmet:启用如下选项,必要时重启 VsCode
三、ES6
入门
自学参考:http://es6.ruanyifeng.com/
1、ECMAScript 6
简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目
标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
1)、ECMAScript
和 JavaScript
的关系:
前者是后者的规范,后者是前者的一种实现。
2)、ES6
与 ECMAScript 2015
的关系:
2、基本语法
ES
标准中不包含 DOM
和BOM
的定义,只涵盖基本数据类型、关键字、语句、运算符、内建对象、内建函数等
通用语法。
本部分只学习前端开发中 ES6
的最少必要知识,方便后面项目开发中对代码的理解。
(1)let
变量作用范围
<script>
// es6 如何定义变量?定义变量特点?
// js 中定义:var t = false;
// es6 写法定义变量,使用关键字 let
// 两者区别:var 没有局部作用域,let 有局部作用域,测试如下
{
var a = 10;
let b = 10;
}
console.log(a);
// 报错:Uncaught ReferenceError: b is not defined
// 变量未被定义
console.log(b);
</script>
(2)let
变量定义特点
<script>
var a = 1;
var a = 2;
// Uncaught SyntaxError: Identifier 'm' has already been declared
// 这个 m 已经被定义了
let m = 10;
let m = 20;
console.log(a);
console.log(m);
</script>
(3)const
声明常量
<script>
// 定义常量
// 声明值之后不允许改变,必须初始化
const PI = "3.1415926";
// 报错:Uncaught TypeError: Assignment to constant variable.
// PI = 3
// Uncaught SyntaxError: Missing initializer in const declaration
const AA;
</script>
(4)数组解构
<script>
// 传统写法
let a = 1, b = 2, c = 3;
console.log(a, b, c);
// es6 写法
let[x, y, z] = [10, 20, 30];
console.log(x, y, z);
</script>
(5)对象解构
<script>
// 定义对象
let user = {
"name" : "yh",
"age" : 15,
"sex" : "男"
};
// 传统
let name1 = user.name;
let age1 = user.age;
let sex1 = user.sex;
console.log(name1, age1, sex1);
// es6
// 注意:变量名要和对象中的属性一致
let {name, age, sex} = user;
console.log(name, age, sex);
</script>
(6)模板字符串
<script>
// 1 使用 ` 实现换行
let str1 = `hello
world!`
console.log(str1);
// 2 在 ` 符号里面可以使用表达式获取变量值
let name = "yh";
let age = 20;
let str2 = `My name is ${name}, age is ${age}, is ${3 * 3}`;
console.log(str2);
// 3 在 ` 符号里面可以调用方法
function function1() {
return "hello fuction1!";
}
let str3 = `demo,${function1()}`;
console.log(str3);
</script>
(7)声明对象简写
<script>
const name = "yh";
const age = 20;
// 传统方式定义对象
const p1 = {
name : name,
age : age
};
console.log(p1);
// es6 方式定义对象
// key 值就是值的变量名
const p2 = {
name,
age
}
console.log(p2);
</script>
(8)对象拓展运算符
<script>
// 对象复制,通过 ... 符号
let person1 = {
name : "yh",
age : 20
};
let person2 = {...person1};
console.log(person2);
// 对象合并
let name = {
name : "mary"
};
let age = {
age : 20
};
let p2 = {
...name,
...age
};
console.log(p2);
</script>
(9)方法简写
<script>
// 传统方式
const person1 = {
sayHi : function() {
console.log("hi");
}
};
// 调用
person1.sayHi();
// es6 方式
const person2 = {
sayHi() {
console.log("hi");
}
};
// 调用
person2.sayHi();
</script>
(10)箭头函数
<script>
// 传统
let f1 = function(a) {
return a;
};
console.log(f1(10));
// 参数 => 函数体
// 使用箭头函数改造
let f2 = m => m;
console.log(f2(20));
// 传统方式
let f3 = function(a, b) {
return a + b;
};
console.log(f3(1, 2));
// 使用箭头函数改造
let f4 = (a, b) => (a + b);
console.log(f3(3, 4));
</script>
四、Vue
入门
1、vue
入门
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue入门</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 插值表达式 -->
{{message}}
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
message : "hello vue"
}
})
</script>
</body>
</html>
2、vue
单向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue单向绑定</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<!--
v-bind 指令
单向数据绑定
这个指令一般用在标签属性里面,获取值
-->
<h1 v-bind:title="message">
{{content}}
</h1>
<!-- 简写方式:就用一个 : -->
<h2 :title="message">
{{content}}
</h2>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
content : "我是标题",
// 获取当前系统的时间(以当前系统的格式显示)
message : "页面加载于 " + new Date().toLocaleDateString()
}
})
</script>
</body>
</html>
3、vue
指令-双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue指令-双向绑定</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<!--
单向绑定
这里变,其他的不会被影响
-->
<input type="text" :value="searchMap.keyword"/>
<!--
双向绑定
一个地方变,其他地方跟着变
-->
<input type="text" v-model="searchMap.keyword"/>
<p>
{{searchMap.keyword}}
</p>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
searchMap : {
keyword : "尚硅谷"
}
}
})
</script>
</body>
</html>
4、vue
事件操作
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue事件操作</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- vue 绑定事件 -->
<button v-on:click="search()">
查询
</button>
<!-- 简写,使用 @ -->
<button @click="f1()">
查询(简写)
</button>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
searchMap : {
keyword : "尚硅谷"
},
// 查询结果
result : {
}
},
// 定义方法,可以定义多个方法
methods : {
search () {
alert("search...")
},
f1 () {
alert("f1....")
}
}
})
</script>
</body>
</html>
5、vue
修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue修饰符</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<form action="save" v-on:submit.prevent="onSubmitForm()">
<input type="text" name="name" v-model="user.name"/>
<button type="submit">保存</button>
</form>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
user : {
}
},
methods : {
onSubmitForm () {
if (this.user.name) {
alert("提交表单");
} else {
alert("请输入用户名")
}
}
}
})
</script>
</body>
</html>
6、vue
条件渲染
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue条件渲染</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<input type="checkbox" v-model="ok"/>是否同意
<h1 v-if="ok">尚硅谷</h1>
<h1 v-else="ok">谷粒学院</h1>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
ok : false
}
})
</script>
</body>
</html>
7、vue
列表渲染
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue列表渲染</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="n in 10">
{{n}}
</li>
</ul>
<hr/>
<ol>
<li v-for="(n, index) in 10">{{n}}---{{index}}</li>
</ol>
<hr/>
<table border="1">
<tr v-for="user in userList">
<td>{{user.id}}</td>
<td>{{user.username}}</td>
<td>{{user.age}}</td>
</tr>
</table>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
userList : [
{
id : 1,
username : "helen",
age : 18
},
{
id : 2,
username : "tom",
age : 28
},
{
id : 1,
username : "jack",
age : 38
}
]
}
})
</script>
</body>
</html>
8、vue
组件
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue组件</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
<Navbar></Navbar>
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
},
// 定义 vue 使用的组件
components : {
'Navbar' : {
// 组件的内容
template : '<ul><li>首页</li><li>学员管理</li></ul>'
}
}
})
</script>
</body>
</html>
9、vue
生命周期
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue生命周期</title>
<script src="vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
// 创建一个 vue 对象
new Vue({
// 绑定 vue 的作用域
el : '#app',
// 定义页面中显示的数据模型
data : {
},
// 在页面渲染之前执行
created () {
// 当程序到这一行就会停止,类似于 debug 的断点
debugger
alert("created");
},
// 在页面渲染之后执行
mounted () {
// 当程序到这一行就会停止,类似于 debug 的断点
debugger
alert("mounted");
}
})
</script>
</body>
</html>
10、vue
路由
<!DOCTYPE html>
<html lang="en">
<head>
<title>vue路由</title>
<!-- 这两个 js 的引入顺序不能改变 -->
<script src="vue.min.js"></script>
<script src="vue-router.min.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<!--
通过 router-link 组件来导航
通过 to 属性指定链接
<router-link> 默认会被渲染一个 <a> 标签
-->
<router-link to="/welcome">首页</router-link>
<router-link to="/student">会员管理</router-link>
<router-link to="/teacher">讲师管理</router-link>
<!--
路由出口
路由匹配到的组件将渲染在这里
-->
<router-view></router-view>
</div>
<script>
// 1、定义路由组件,可以从其他文件导入进来
const Welcome = {
template : '<div>欢迎</div>'
}
const Student = {
template : '<div>Student List</div>'
}
const Teacher = {
template : '<div>Teacher List</div>'
}
// 2、定义路由,每个路由应该映射一个组件
const routes = [
{
path : '/',
redirect : '/Welcome'
},
{
path : '/welcome',
component : Welcome
},
{
path : '/student',
component : Student
},
{
path : "/teacher",
component : Teacher
}
];
// 3、创建 router 实例,然后传 routes 配置
const router = new VueRouter({
// 缩写,相当于:routes : routes
routes
});
// 4、创建和挂载根实例,从而让整个应用都有路由功能
const app = new Vue({
el : '#app',
router
})
</script>
</body>
</html>