小帽学堂
第六章 统一异常处理
创建统一异常处理器
在service-base中创建统一异常处理类GlobalExceptionHandler.java
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler ( Exception . class )
@ResponseBody
public R error ( Exception e) {
e. printStackTrace ( ) ;
return R . error ( ) . message ( "执行了全局异常处理.." ) ;
}
@ExceptionHandler ( ArithmeticException . class )
@ResponseBody
public R error ( ArithmeticException e) {
e. printStackTrace ( ) ;
return R . error ( ) . message ( "执行了ArithmeticException异常处理.." ) ;
}
@ExceptionHandler ( LemonException . class )
@ResponseBody
public R error ( LemonException e) {
e. printStackTrace ( ) ;
return R . error ( ) . code ( e. getCode ( ) ) . message ( e. getMsg ( ) ) ;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LemonException extends RuntimeException {
private Integer code;
private String msg;
}
第七章 统一日志处理
一、日志
配置日志级别
日志记录器(Logger)的行为是分等级的。如下表所示: 分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL 默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别
logging.level.root= WARN
二、 Logback日志
spring boot内部使用Logback作为日志实现的框架。
1. 配置logback日志
删除application.properties中的日志配置 安装idea彩色日志插件:grep-console(IDEA默认有) resources 中创建 logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
< configuration scan = " true" scanPeriod = " 10 seconds" >
< contextName> logback</ contextName>
< property name = " log.path" value = " D:/lemon_1010/edu" />
< 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" >
< filter class = " ch.qos.logback.classic.filter.ThresholdFilter" >
< level> INFO</ level>
</ filter>
< encoder>
< Pattern> ${CONSOLE_LOG_PATTERN}</ Pattern>
< charset> UTF-8</ charset>
</ encoder>
</ appender>
< 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>
< filter class = " ch.qos.logback.classic.filter.LevelFilter" >
< level> INFO</ level>
< onMatch> ACCEPT</ onMatch>
< onMismatch> DENY</ onMismatch>
</ filter>
</ appender>
< 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>
< filter class = " ch.qos.logback.classic.filter.LevelFilter" >
< level> warn</ level>
< onMatch> ACCEPT</ onMatch>
< onMismatch> DENY</ onMismatch>
</ filter>
</ appender>
< 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>
< filter class = " ch.qos.logback.classic.filter.LevelFilter" >
< level> ERROR</ level>
< onMatch> ACCEPT</ onMatch>
< onMismatch> DENY</ onMismatch>
</ filter>
</ appender>
< springProfile name = " dev" >
< logger name = " com.alex" level = " INFO" />
< 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());
第八章 前端技术
一、前端开发
前端工程师“Front-End-Developer”源自于美国。大约从2005年开始正式的前端工程师角色被行业所认可,到了2010年,互联网开始全面进入移动时代,前端开发的工作越来越重要。 最初所有的开发工作都是由后端工程师完成的,随着业务越来越繁杂,工作量变大,于是我们将项目中的可视化部分和一部分交互功能的开发工作剥离出来,形成了前端开发。 由于互联网行业的急速发展,导致了在不同的国家,有着截然不同的分工体制。 在日本和一些人口比较稀疏的国家,例如加拿大、澳洲等,流行“Full-Stack Engineer”,也就是我们通常所说的全栈工程师。通俗点说就是一个人除了完成前端开发和后端开发工作以外,有的公司从产品设计到项目开发再到后期运维可能都是同一个人,甚至可能还要负责UI、配动画,也可以是扫地、擦窗、写文档、维修桌椅等等。 而在美国等互联网环境比较发达的国家项目开发的分工协作更为明确,整个项目开发分为前端、中间层和后端三个开发阶段,这三个阶段分别由三个或者更多的人来协同完成。 国内的大部分互联网公司只有前端工程师和后端工程师,中间层的工作有的由前端来完成,有的由后端来完成。 PRD(产品原型-产品经理) - PSD(视觉设计-UI工程师) - HTML/CSS/JavaScript(PC/移动端网页,实现网页端的视觉展示和交互-前端工程师)
二、vscode初始设置
1. 中文界面配置
首先安装中文插件:Chinese (Simplified) Language Pack for Visual Studio Code 右下角弹出是否重启vs,点击“yes” 有些机器重启后如果界面没有变化,则 点击 左边栏Manage -> Command Paletet…【Ctrl+Shift+p】 在搜索框中输入“configure display language”,回车 打开locale.json文件,修改文件下的属性 “locale”:“zh-cn” 重启vs
2. 插件安装
为方便后续开发,建议安装如下插件(红色矩形框标记的插件)
3. 创建项目
vscode本身没有新建项目的选项,所以要先创建一个空的文件夹,如project_xxxx。 然后打开vscode,再在vscode里面选择 File -> Open Folder 打开文件夹,这样才可以创建项目。
4. 保存工作区
打开文件夹后,选择“文件 -> 将工作区另存为…”,为工作区文件起一个名字,存储在刚才的文件夹下即可。
5. 新建文件夹和网页
6. 预览网页
以文件路径方式打开网页预览
需要安装“open in browser”插件: 文件右键 -> Open In Default Browser 以服务器方式打开网页预览
需要安装“Live Server”插件: 文件右键 -> Open with Live Server
7. 设置字体大小
左边栏Manage -> settings -> 搜索 “font” -> Font size
8. 开启完整的Emmet语法支持
设置中搜索 Emmet:启用如下选项,必要时重启vs
三、ES6简介
1. ECMAScript 6 简介
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。 ECMAScript 和 JavaScript 的关系
一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系? 要讲清楚这个问题,需要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。 因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript) ES6 与 ECMAScript 2015 的关系
ECMAScript 2015(简称 ES2015)这个词,也是经常可以看到的。它与 ES6 是什么关系呢? 2011 年,ECMAScript 5.1 版发布后,就开始制定 6.0 版了。因此,ES6 这个词的原意,就是指 JavaScript 语言的下一个版本。 ES6 的第一个版本,在 2015 年 6 月发布,正式名称是《ECMAScript 2015 标准》(简称 ES2015)。 2016 年 6 月,小幅修订的《ECMAScript 2016 标准》(简称 ES2016)如期发布,这个版本可以看作是 ES6.1 版,因为两者的差异非常小,基本上是同一个标准。根据计划,2017 年 6 月发布 ES2017 标准。 因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。本书中提到 ES6 的地方,一般是指 ES2015 标准,但有时也是泛指“下一代 JavaScript 语言”。
2. ES6基本语法
2.1 let 定义变量和常量
{
var a = 0
let b = 1
}
console. log ( a)
console. log ( b)
var m = 1
var m = 2
let n = 3
let n = 4
console. log ( m)
console. log ( n)
2.2 const声明常量(只读变量)
const PI = "3.1415926"
PI = 3
const MY_AGE
2.3 解构赋值
解构赋值是对赋值运算符的扩展。 它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。 在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。
let a = 1 , b = 2 , c = 3
console. log ( a, b, c)
let [ x, y, z] = [ 1 , 2 , 3 ]
console. log ( x, y, z)
let user = { name : 'Helen' , age : 18 }
let name1 = user. name
let age1 = user. age
console. log ( name1, age1)
let { name, age } = user
console. log ( name, age)
2.4 模板字符串
模板字符串相当于加强版的字符串,用反引号 ` 除了作为普通字符串,还可以用来定义多行字符串,还可以在字符串中加入变量和表达式。
let string1 = ` Hey,
can you stop angry now? `
console. log ( string1)
let name = "Mike"
let age = 27
let info = ` My Name is ${ name} ,I am ${ age+ 1 } years old next year. `
console. log ( info)
function f ( ) {
return "have fun!"
}
let string2 = ` Game start, ${ f ( ) } `
console. log ( string2) ;
2.5 声明对象简写
const age = 12
const name = "Amy"
const person1 = { age : age, name : name}
console. log ( person1)
const person2 = { age, name}
console. log ( person2)
2.6 定义方法简写
const person1 = {
sayHi : function ( ) {
console. log ( "Hi" )
}
}
person1. sayHi ( )
const person2 = {
sayHi ( ) {
console. log ( "Hi" )
}
}
2.7 对象拓展运算符
拓展运算符(…)用于取出参数对象所有可遍历属性然后拷贝到当前对象。
let person1 = { name : "Amy" , age : 15 }
let someone = { ... person1 }
console. log ( someone)
let age = { age : 15 }
let name = { name : "Amy" }
let person2 = { ... age, ... name}
console. log ( person2)
2.8 箭头函数
箭头函数提供了一种更加简洁的函数书写方式。基本语法是:
箭头函数多用于匿名函数的定义
var f1 = function ( a ) {
return a
}
console. log ( f1 ( 1 ) )
var f2 = a => a
console. log ( f2 ( 1 ) )
var f3 = ( a, b ) => {
let result = a+ b
return result
}
console. log ( f3 ( 6 , 2 ) )
var f4 = ( a, b ) => a+ b
四、Vue.js 入门
1. 介绍
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。 Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
2. 初始Vue.js
< div id = " app" >
{{ message }}
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
message : 'Hello Vue!'
}
} )
</ script>
这就是声明式渲染:Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统 这里的核心思想就是没有繁琐的DOM操作,例如jQuery中,我们需要先找到div节点,获取到DOM对象,然后进行一系列的节点操作 在vs code中创建代码片段:
文件 => 首选项 => 用户代码片段 => 新建全局代码片段/或文件夹代码片段:vue-html.code-snippets 注意:制作代码片段的时候,字符串中如果包含文件中复制过来的“Tab”键的空格,要换成“空格键”的空格 使用时输入 vuehtml 固定代码自动生成
{
"vue htm" : {
"scope" : "html" ,
"prefix" : "vuehtml" ,
"body" : [
"<!DOCTYPE html>" ,
"<html lang=\"en\">" ,
"" ,
"<head>" ,
" <meta charset=\"UTF-8\">" ,
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" ,
" <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">" ,
" <title>Document</title>" ,
"</head>" ,
"" ,
"<body>" ,
" <div id=\"app\">" ,
"" ,
" </div>" ,
" <script src=\"vue.min.js\"></script>" ,
" <script>" ,
" new Vue({" ,
" el: '#app'," ,
" data: {" ,
" $1" ,
" }" ,
" })" ,
" </script>" ,
"</body>" ,
"" ,
"</html>" ,
] ,
"description" : "my vue template in html"
}
}
3. 基本语法
3.1 基本数据渲染和指令
v-bind 特性被称为指令。指令带有前缀 v- 除了使用插值表达式{{}}进行数据渲染,也可以使用 v-bind指令,它的简写的形式就是一个冒号(:)
< body>
< div id = " app" >
< h1 v-bind: title= " message" >
{{content}}
</ h1>
< h2 :title = " message" >
{{content}}
</ h2>
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
content : '我是标题' ,
message : '页面加载于 ' + new Date ( ) . toLocaleString ( )
}
} )
</ script>
</ body>
3.2 双向数据绑定
双向数据绑定和单向数据绑定:使用 v-model 进行双向数据绑定
< body>
< div id = " app" >
< input type = " text" v-bind: value= " searchMap.keyWord" />
< input type = " text" v-model = " searchMap.keyWord" />
< p> {{searchMap.keyWord}}</ p>
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
searchMap : {
keyWord : '小帽学堂'
}
}
} )
</ script>
</ body>
3.3 事件
需求:点击查询按钮,按照输入框中输入的内容查找公司相关信息 在前面的例子基础上,data节点中增加 result,增加 methods 节点 并定义 search 方法
< body>
< div id = " app" >
< button v-on: click= " search()" > 查询</ button>
< button @click = " search()" > 查询1</ button>
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
searchMap : {
keyWord : '小帽学堂'
} ,
result : { }
} ,
methods : {
search ( ) {
console. log ( 'search....' )
} ,
f1 ( ) {
console. log ( 'f1...' )
}
}
} )
</ script>
</ body>
3.4 vue修饰符
修饰符 (Modifiers) 是以半角句号(.)指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。 例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():即阻止事件原本的默认行为
< body>
< div id = " app" >
< form action = " save" v-on: submit.prevent= " onSubmit" >
< input type = " text" id = " name" v-model = " user.username" />
< button type = " submit" > 保存</ button>
</ form>
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
user : { }
} ,
methods : {
onSubmit ( ) {
if ( this . user. username) {
console. log ( '提交表单' )
} else {
alert ( '请输入用户名' )
}
}
}
} )
</ script>
</ body>
3.5 条件渲染
v-if:条件指令 v-show:条件指令 v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if 也是惰性的 :如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< meta http-equiv = " X-UA-Compatible" content = " ie=edge" >
< title> Document</ title>
</ head>
< body>
< div id = " app" >
< input type = " checkbox" v-model = " ok" /> 是否同意
< h1 v-if = " ok" > 小帽</ h1>
< h1 v-else > 小帽学堂</ h1>
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
ok : false
}
} )
</ script>
</ body>
</ html>
3.6 列表渲染
< body>
< div id = " app" >
< ul>
< li v-for = " n in 10" > {{n}} </ li>
</ ul>
< 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 src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
userList : [
{ id : 1 , username : 'helen' , age : 18 } ,
{ id : 2 , username : 'peter' , age : 28 } ,
{ id : 3 , username : 'andy' , age : 38 }
]
}
} )
</ script>
</ body>
五、Vue.js 进阶
1. 组件
组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素,封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
1.1 局部组件
< body>
< div id = " app" >
< Navbar> </ Navbar>
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
components : {
'Navbar' : {
template : '<ul><li>首页</li><li>学员管理</li></ul>'
}
}
} )
</ script>
</ body>
1.2 全局组件
定义全局组件:components/Navbar.js
Vue. component ( 'Navbar' , {
template : '<ul><li>首页</li><li>学员管理</li><li>讲师管理</li></ul>'
} )
< div id = " app" >
< Navbar> </ Navbar>
</ div>
< script src = " vue.min.js" > </ script>
< script src = " components/Navbar.js" > </ script>
< script>
var app = new Vue ( {
el : '#app'
} )
</ script>
2. 实例生命周期
< body>
< div id = " app" >
hello
</ div>
< script src = " vue.min.js" > </ script>
< script>
new Vue ( {
el : '#app' ,
data : {
} ,
created ( ) {
debugger
console. log ( 'created....' )
} ,
mounted ( ) {
debugger
console. log ( 'mounted....' )
}
} )
</ script>
</ body>
beforeCreate ( ) {
console. log ( this . message)
this . show ( )
} ,
created ( ) {
console. log ( this . message)
this . show ( )
} ,
beforeMount ( ) {
console. log ( document. getElementById ( 'h3' ) . innerText)
} ,
mounted ( ) {
console. log ( document. getElementById ( 'h3' ) . innerText)
} ,
beforeUpdate ( ) {
console. log ( '界面显示的内容:' + document. getElementById ( 'h3' ) . innerText)
console. log ( 'data 中的 message 数据是:' + this . message)
} ,
updated ( ) {
console. log ( '界面显示的内容:' + document. getElementById ( 'h3' ) . innerText)
console. log ( 'data 中的 message 数据是:' + this . message)
}
3. 路由
Vue.js 路由允许我们通过不同的 URL 访问不同的内容。 通过 Vue.js 可以实现多视图的单页Web应用(single page web application,SPA)。 Vue.js 路由需要载入 vue-router 库。
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< meta http-equiv = " X-UA-Compatible" content = " ie=edge" >
< title> Document</ title>
</ head>
< body>
< div id = " app" >
< h1> Hello App!</ h1>
< p>
< router-link to = " /" > 首页</ router-link>
< router-link to = " /student" > 会员管理</ router-link>
< router-link to = " /teacher" > 讲师管理</ router-link>
</ p>
< router-view> </ router-view>
</ div>
< script src = " vue.min.js" > </ script>
< script src = " vue-router.min.js" > </ script>
< script>
const Welcome = { template : '<div>欢迎</div>' }
const Student = { template : '<div>student list</div>' }
const Teacher = { template : '<div>teacher list</div>' }
const routes = [
{ path : '/' , redirect : '/welcome' } ,
{ path : '/welcome' , component : Welcome } ,
{ path : '/student' , component : Student } ,
{ path : '/teacher' , component : Teacher }
]
const router = new VueRouter ( {
routes
} )
const app = new Vue ( {
el : '#app' ,
router
} )
</ script>
</ body>
</ html>