-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 78.2 KB
/
content.json
1
{"meta":{"title":"Wangd1's Blog","subtitle":"可山水万程,再难遇你","description":null,"author":"Wangd1","url":"https://s.wangd1.top","root":"/"},"pages":[{"title":"我","date":"2019-04-23T14:14:36.000Z","updated":"2023-04-21T10:46:34.127Z","comments":false,"path":"about/index.html","permalink":"https://s.wangd1.top/about/index.html","excerpt":"","text":"[桃李春风一杯酒,江湖夜雨十年灯] 我是 Wangdi,一枚小程序员。 专注 Java 开发,偶尔写写前端。 关注新技术,喜欢游戏,喜欢运动,偶尔旅行。"},{"title":"bangumi","date":"2019-02-10T13:32:48.000Z","updated":"2023-04-17T07:27:28.343Z","comments":false,"path":"bangumi/index.html","permalink":"https://s.wangd1.top/bangumi/index.html","excerpt":"","text":""},{"title":"留言板","date":"2019-04-23T15:13:48.000Z","updated":"2023-04-17T07:27:28.344Z","comments":true,"path":"comment/index.html","permalink":"https://s.wangd1.top/comment/index.html","excerpt":"","text":"念两句诗 叙别梦、扬州一觉。 【宋代】吴文英《夜游宫·人去西楼雁杳》"},{"title":"client","date":"2018-12-20T15:13:35.000Z","updated":"2023-04-17T07:27:28.343Z","comments":false,"path":"client/index.html","permalink":"https://s.wangd1.top/client/index.html","excerpt":"","text":"直接下载 or 扫码下载:"},{"title":"lab","date":"2019-01-05T13:47:59.000Z","updated":"2023-04-17T07:27:28.345Z","comments":false,"path":"lab/index.html","permalink":"https://s.wangd1.top/lab/index.html","excerpt":"","text":"sakura主题balabala"},{"title":"给我留言吧~","date":"2020-07-29T06:44:56.000Z","updated":"2023-04-17T07:27:28.345Z","comments":true,"path":"guestbook/index.html","permalink":"https://s.wangd1.top/guestbook/index.html","excerpt":"","text":""},{"title":"donate","date":"2018-12-20T15:13:05.000Z","updated":"2023-04-17T07:27:28.344Z","comments":false,"path":"donate/index.html","permalink":"https://s.wangd1.top/donate/index.html","excerpt":"","text":""},{"title":"links","date":"2018-12-19T15:11:06.000Z","updated":"2023-04-17T07:27:28.346Z","comments":true,"path":"links/index.html","permalink":"https://s.wangd1.top/links/index.html","excerpt":"","text":""},{"title":"歌曲","date":"2019-07-03T10:27:32.000Z","updated":"2023-04-17T07:27:28.346Z","comments":false,"path":"playlist/index.html","permalink":"https://s.wangd1.top/playlist/index.html","excerpt":"","text":""},{"title":"theme-sakura","date":"2019-01-04T14:53:25.000Z","updated":"2023-04-17T07:27:28.347Z","comments":false,"path":"theme-sakura/index.html","permalink":"https://s.wangd1.top/theme-sakura/index.html","excerpt":"","text":"Hexo主题Sakura修改自WordPress主题Sakura,感谢原作者Mashiro"},{"title":"标签","date":"2019-07-03T03:18:57.000Z","updated":"2023-04-17T07:27:28.347Z","comments":false,"path":"tags/index.html","permalink":"https://s.wangd1.top/tags/index.html","excerpt":"","text":""},{"title":"video","date":"2018-12-20T15:14:38.000Z","updated":"2023-04-17T07:27:28.348Z","comments":false,"path":"video/index.html","permalink":"https://s.wangd1.top/video/index.html","excerpt":"","text":"var videos = [ { img: 'https://lain.bgm.tv/pic/cover/l/0e/1e/218971_2y351.jpg', title: '朝花夕誓——于离别之朝束起约定之花', status: '已追完', progress: 100, jp: 'さよならの朝に約束の花をかざろう', time: '放送时间: 2018-02-24 SUN.', desc: ' 住在远离尘嚣的土地,一边将每天的事情编织成名为希比欧的布,一边静静生活的伊欧夫人民。在15岁左右外表就停止成长,拥有数百年寿命的他们,被称为“离别的一族”,并被视为活着的传说。没有双亲的伊欧夫少女玛奇亚,过着被伙伴包围的平稳日子,却总感觉“孤身一人”。他们的这种日常,一瞬间就崩溃消失。追求伊欧夫的长寿之血,梅萨蒂军乘坐着名为雷纳特的古代兽发动了进攻。在绝望与混乱之中,伊欧夫的第一美女蕾莉亚被梅萨蒂带走,而玛奇亚暗恋的少年克里姆也失踪了。玛奇亚虽然总算逃脱了,却失去了伙伴和归去之地……。' }, { img : 'https://lain.bgm.tv/pic/cover/l/0e/1e/218971_2y351.jpg', title: '朝花夕誓——于离别之朝束起约定之花', status: '已追完', progress: 100, jp: 'さよならの朝に約束の花をかざろう', time: '2018-02-24 SUN.', desc: ' 住在远离尘嚣的土地,一边将每天的事情编织成名为希比欧的布,一边静静生活的伊欧夫人民。在15岁左右外表就停止成长,拥有数百年寿命的他们,被称为“离别的一族”,并被视为活着的传说。没有双亲的伊欧夫少女玛奇亚,过着被伙伴包围的平稳日子,却总感觉“孤身一人”。他们的这种日常,一瞬间就崩溃消失。追求伊欧夫的长寿之血,梅萨蒂军乘坐着名为雷纳特的古代兽发动了进攻。在绝望与混乱之中,伊欧夫的第一美女蕾莉亚被梅萨蒂带走,而玛奇亚暗恋的少年克里姆也失踪了。玛奇亚虽然总算逃脱了,却失去了伙伴和归去之地……。' } ] .should-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:95%;}.should-ellipsis-full{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%;}.should-ellipsis i{position:absolute;right:24px;}.grey-text{color:#9e9e9e !important}.grey-text.text-darken-4{color:#212121 !important}html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}img{border-style:none}progress{display:inline-block;vertical-align:baseline}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,*:before,*:after{-webkit-box-sizing:inherit;box-sizing:inherit}ul:not(.browser-default){padding-left:0;list-style-type:none}ul:not(.browser-default)>li{list-style-type:none}.card{-webkit-box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2);box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}.hoverable{-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s,-webkit-box-shadow .25s}.hoverable:hover{-webkit-box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}i{line-height:inherit}i.right{float:right;margin-left:15px}.bangumi .right{float:right !important}.material-icons{text-rendering:optimizeLegibility;-webkit-font-feature-settings:'liga';-moz-font-feature-settings:'liga';font-feature-settings:'liga'}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:\"\";display:table;clear:both}.row .col{float:left;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0 .75rem;min-height:1px}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}@media only screen and (min-width:601px){.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}}html{line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-weight:normal;color:rgba(0,0,0,0.87)}@media only screen and (min-width:0){html{font-size:14px}}@media only screen and (min-width:992px){html{font-size:14.5px}}@media only screen and (min-width:1200px){html{font-size:15px}}.card{position:relative;margin:.5rem 0 1rem 0;background-color:#fff;-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s,-webkit-box-shadow .25s;border-radius:2px}.card .card-title{font-size:24px;font-weight:300}.card .card-title.activator{cursor:pointer}.card .card-image{position:relative}.card .card-image img{display:block;border-radius:2px 2px 0 0;position:relative;left:0;right:0;top:0;bottom:0;width:100%}.card .card-content{padding:24px;border-radius:0 0 2px 2px}.card .card-content p{margin:0}.card .card-content .card-title{display:block;line-height:32px;margin-bottom:8px}.card .card-content .card-title i{line-height:32px}.card .card-reveal{padding:24px;position:absolute;background-color:#fff;width:100%;overflow-y:auto;left:0;top:100%;height:100%;z-index:3;display:none}.card .card-reveal .card-title{cursor:pointer;display:block}.waves-effect{position:relative;cursor:pointer;display:inline-block;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle;z-index:1;-webkit-transition:.3s ease-out;transition:.3s ease-out}.waves-effect img{position:relative;z-index:-1}.waves-block{display:block}::-webkit-input-placeholder{color:#d1d1d1}::-moz-placeholder{color:#d1d1d1}:-ms-input-placeholder{color:#d1d1d1}::-ms-input-placeholder{color:#d1d1d1}[type=\"radio\"]:not(:checked){position:absolute;opacity:0;pointer-events:none}[type=\"radio\"]:not(:checked)+span{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-transition:.28s ease;transition:.28s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type=\"radio\"]:not(:checked)+span:before,[type=\"radio\"]:not(:checked)+span:after{border-radius:50%}[type=\"radio\"]:not(:checked)+span:before,[type=\"radio\"]:not(:checked)+span:after{border:2px solid #5a5a5a}[type=\"radio\"]:not(:checked)+span:after{-webkit-transform:scale(0);transform:scale(0)}[type=\"checkbox\"]:not(:checked){position:absolute;opacity:0;pointer-events:none}[type=\"checkbox\"]:not(:checked):disabled+span:not(.lever):before{border:none;background-color:rgba(0,0,0,0.42)}[type=\"checkbox\"].filled-in:not(:checked)+span:not(.lever):before{width:0;height:0;border:3px solid transparent;left:6px;top:10px;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type=\"checkbox\"].filled-in:not(:checked)+span:not(.lever):after{height:20px;width:20px;background-color:transparent;border:2px solid #5a5a5a;top:0px;z-index:0}input[type=checkbox]:not(:disabled) ~ .lever:active:before,input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before{-webkit-transform:scale(2.4);transform:scale(2.4);background-color:rgba(0,0,0,0.08)}input[type=range].focused:focus:not(.active)::-webkit-slider-thumb{-webkit-box-shadow:0 0 0 10px rgba(38,166,154,0.26);box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range].focused:focus:not(.active)::-moz-range-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range].focused:focus:not(.active)::-ms-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)} 番组计划 这里将是永远的回忆 window.onload = function(){ videos.forEach(function(video, i){ $('#rootRow').append(` ${video.title} ${video.jp} ${video.status} ${video.title} ${video.jp} 放送时间: ${video.time} ${video.desc} ${video.status} `) }) }"},{"title":"rss","date":"2018-12-20T15:09:03.000Z","updated":"2023-04-17T07:27:28.346Z","comments":true,"path":"rss/index.html","permalink":"https://s.wangd1.top/rss/index.html","excerpt":"","text":""}],"posts":[{"title":"数据库设计中的14个技巧","slug":"other/数据库设计中的14个技巧","date":"2023-04-17T07:27:28.337Z","updated":"2023-04-17T07:27:28.337Z","comments":true,"path":"archives/8278.html","link":"","permalink":"https://s.wangd1.top/archives/8278.html","excerpt":"转自 [https://blog.csdn.net/sirfei/article/details/434994 1. 原始单据与实体之间的关系 &emsp;&emsp;可以是一对一、一对多、多对多的关系。在一般情况下,它们是一对一的关系:即一张原始单据对 应且只对应一个实体。在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实 体,或多张原始单证对应一个实体。这里的实体可以理解为基本表。明确这种对应关系后,对我们设计 录入界面大有好处。 〖例1〗:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表、社会 关系表、工作简历表。这就是“一张原始单证对应多个实体”的典型例子。","text":"转自 [https://blog.csdn.net/sirfei/article/details/434994 1. 原始单据与实体之间的关系 &emsp;&emsp;可以是一对一、一对多、多对多的关系。在一般情况下,它们是一对一的关系:即一张原始单据对 应且只对应一个实体。在特殊情况下,它们可能是一对多或多对一的关系,即一张原始单证对应多个实 体,或多张原始单证对应一个实体。这里的实体可以理解为基本表。明确这种对应关系后,对我们设计 录入界面大有好处。 〖例1〗:一份员工履历资料,在人力资源信息系统中,就对应三个基本表:员工基本情况表、社会 关系表、工作简历表。这就是“一张原始单证对应多个实体”的典型例子。 2. 主键与外键 &emsp;&emsp;一般而言,一个实体不能既无主键又无外键。在E—R 图中, 处于叶子部位的实体, 可以定义主键, 也可以不定义主键(因为它无子孙), 但必须要有外键(因为它有父亲)。 主键与外键的设计,在全局数据库的设计中,占有重要地位。当全局数据库的设计完成以后,有个 美国数据库设计专家说:“键,到处都是键,除了键之外,什么也没有”,这就是他的数据库设计经验 之谈,也反映了他对信息系统核心(数据模型)的高度抽象思想。因为:主键是实体的高度抽象,主键与 外键的配对,表示实体之间的连接。 3. 基本表的性质 &emsp;&emsp;基本表与中间表、临时表不同,因为它具有如下四个特性: (1) 原子性。基本表中的字段是不可再分解的。 (2) 原始性。基本表中的记录是原始数据(基础数据)的记录。 (3) 演绎性。由基本表与代码表中的数据,可以派生出所有的输出数据。 (4) 稳定性。基本表的结构是相对稳定的,表中的记录是要长期保存的。 理解基本表的性质后,在设计数据库时,就能将基本表与中间表、临时表区分开来。 4. 范式标准 &emsp;&emsp;基本表及其字段之间的关系, 应尽量满足第三范式。但是,满足第三范式的数据库设计,往往不是 最好的设计。为了提高数据库的运行效率,常常需要降低范式标准:适当增加冗余,达到以空间换时间 的目的。 〖例2〗:有一张存放商品的基本表,如表1所示。“金额”这个字段的存在,表明该表的设计不满 足第三范式,因为“金额”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加 “金额”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。 在Rose 2002中,规定列有两种类型:数据列和计算列。“金额”这样的列被称为“计算列”,而“ 单价”和“数量”这样的列被称为“数据列”。 表1 商品表的表结构 商品名称 商品型号 单价 数量 金额 电视机 29吋 2,500 40 100,000 5. 通俗地理解三个范式 &emsp;&emsp;通俗地理解三个范式,对于数据库设计大有好处。在数据库设计中,为了更好地应用三个范式,就 必须通俗地理解三个范式(通俗地理解是够用的理解,并不是最科学最准确的理解): 第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解; 第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性; 第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余 。 没有冗余的数据库设计可以做到。但是,没有冗余的数据库未必是最好的数据库,有时为了提高运 行效率,就必须降低范式标准,适当保留冗余数据。具体做法是:在概念数据模型设计时遵守第三范式 ,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余。 6. 要善于识别与正确处理多对多的关系 &emsp;&emsp;若两个实体之间存在多对多的关系,则应消除这种关系。消除的办法是,在两者之间增加第三个实 体。这样,原来一个多对多的关系,现在变为两个一对多的关系。要将原来两个实体的属性合理地分配 到三个实体中去。这里的第三个实体,实质上是一个较复杂的关系,它对应一张基本表。一般来讲,数 据库设计工具不能识别多对多的关系,但能处理多对多的关系。 〖例3〗:在“图书馆信息系统”中,“图书”是一个实体,“读者”也是一个实体。这两个实体之 间的关系,是一个典型的多对多关系:一本图书在不同时间可以被多个读者借阅,一个读者又可以借多 本图书。为此,要在二者之间增加第三个实体,该实体取名为“借还书”,它的属性为:借还时间、借 还标志(0表示借书,1表示还书),另外,它还应该有两个外键(“图书”的主键,“读者”的主键),使 它能与“图书”和“读者”连接。 7. 主键PK的取值方法 &emsp;&emsp;PK是供程序员使用的表间连接工具,可以是一无物理意义的数字串, 由程序自动加1来实现。也可 以是有物理意义的字段名或字段名的组合。不过前者比后者好。当PK是字段名的组合时,建议字段的个 数不要太多,多了不但索引占用空间大,而且速度也慢。 8. 正确认识数据冗余 &emsp;&emsp;主键与外键在多表中的重复出现, 不属于数据冗余,这个概念必须清楚,事实上有许多人还不清楚 。非键字段的重复出现, 才是数据冗余!而且是一种低级冗余,即重复性的冗余。高级冗余不是字段的 重复出现,而是字段的派生出现。 〖例4〗:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出 来的,它就是冗余,而且是一种高级冗余。冗余的目的是为了提高处理速度。只有低级冗余才会增加数 据的不一致性,因为同一数据,可能从不同时间、地点、角色上多次录入。因此,我们提倡高级冗余(派 生性冗余),反对低级冗余(重复性冗余)。 9. E–R图没有标准答案 &emsp;&emsp;信息系统的E–R图没有标准答案,因为它的设计与画法不是惟一的,只要它覆盖了系统需求的业务 范围和功能内容,就是可行的。反之要修改E–R图。尽管它没有惟一的标准答案,并不意味着可以随意 设计。好的E—R图的标准是:结构清晰、关联简洁、实体个数适中、属性分配合理、没有低级冗余。 10. 视图技术在数据库设计中很有用 &emsp;&emsp;与基本表、代码表、中间表不同,视图是一种虚表,它依赖数据源的实表而存在。视图是供程序员 使用数据库的一个窗口,是基表数据综合的一种形式, 是数据处理的一种方法,是用户数据保密的一种 手段。为了进行复杂处理、提高运算速度和节省存储空间, 视图的定义深度一般不得超过三层。 若三层 视图仍不够用, 则应在视图上定义临时表, 在临时表上再定义视图。这样反复交迭定义, 视图的深度就 不受限制了。 对于某些与国家政治、经济、技术、军事和安全利益有关的信息系统,视图的作用更加重要。这些 系统的基本表完成物理设计之后,立即在基本表上建立第一层视图,这层视图的个数和结构,与基本表 的个数和结构是完全相同。并且规定,所有的程序员,一律只准在视图上操作。只有数据库管理员,带 着多个人员共同掌握的“安全钥匙”,才能直接在基本表上操作。请读者想想:这是为什么? 11. 中间表、报表和临时表 &emsp;&emsp;中间表是存放统计数据的表,它是为数据仓库、输出报表或查询结果而设计的,有时它没有主键与 外键(数据仓库除外)。临时表是程序员个人设计的,存放临时记录,为个人所用。基表和中间表由DBA维 护,临时表由程序员自己用程序自动维护。 12. 完整性约束表现在三个方面 &emsp;&emsp;域的完整性:用Check来实现约束,在数据库设计工具中,对字段的取值范围进行定义时,有一个Ch eck按钮,通过它定义字段的值城。 参照完整性:用PK、FK、表级触发器来实现。 用户定义完整性:它是一些业务规则,用存储过程和触发器来实现。 13. 防止数据库设计打补丁的方法是“三少原则” &emsp;&emsp;(1) 一个数据库中表的个数越少越好。只有表的个数少了,才能说明系统的E–R图少而精,去掉了 重复的多余的实体,形成了对客观世界的高度抽象,进行了系统的数据集成,防止了打补丁式的设计; &emsp;&emsp;(2) 一个表中组合主键的字段个数越少越好。因为主键的作用,一是建主键索引,二是做为子表的 外键,所以组合主键的字段个数少了,不仅节省了运行时间,而且节省了索引存储空间; &emsp;&emsp;(3) 一个表中的字段个数越少越好。只有字段的个数少了,才能说明在系统中不存在数据重复,且 很少有数据冗余,更重要的是督促读者学会“列变行”,这样就防止了将子表中的字段拉入到主表中去 ,在主表中留下许多空余的字段。所谓“列变行”,就是将主表中的一部分内容拉出去,另外单独建一 个子表。这个方法很简单,有的人就是不习惯、不采纳、不执行。 数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点。“三少”是一个整体概 念,综合观点,不能孤立某一个原则。该原则是相对的,不是绝对的。“三多”原则肯定是错误的。试 想:若覆盖系统同样的功能,一百个实体(共一千个属性) 的E–R图,肯定比二百个实体(共二千个属性) 的E–R图,要好得多。 提倡“三少”原则,是叫读者学会利用数据库设计技术进行系统的数据集成。数据集成的步骤是将 文件系统集成为应用数据库,将应用数据库集成为主题数据库,将主题数据库集成为全局综合数据库。 集成的程度越高,数据共享性就越强,信息孤岛现象就越少,整个企业信息系统的全局E—R图中实体的 个数、主键的个数、属性的个数就会越少。 提倡“三少”原则的目的,是防止读者利用打补丁技术,不断地对数据库进行增删改,使企业数据 库变成了随意设计数据库表的“垃圾堆”,或数据库表的“大杂院”,最后造成数据库中的基本表、代 码表、中间表、临时表杂乱无章,不计其数,导致企事业单位的信息系统无法维护而瘫痪。 “三多”原则任何人都可以做到,该原则是“打补丁方法”设计数据库的歪理学说。“三少”原则 是少而精的原则,它要求有较高的数据库设计技巧与艺术,不是任何人都能做到的,因为该原则是杜绝 用“打补丁方法”设计数据库的理论依据 14. 提高数据库运行效率的办法 &emsp;&emsp;在给定的系统硬件和系统软件条件下,提高数据库系统的运行效率的办法是: (1) 在数据库物理设计时,降低范式,增加冗余, 少用触发器, 多用存储过程。 (2) 当计算非常复杂、而且记录条数非常巨大时(例如一千万条),复杂计算要先在数据库外面,以 文件系统方式用C++语言计算处理完成之后,最后才入库追加到表中去。这是电信计费系统设计的经验。 (3) 发现某个表的记录太多,例如超过一千万条,则要对该表进行水平分割。水平分割的做法是, 以该表主键PK的某个值为界线,将该表的记录水平分割为两个表。若发现某个表的字段太多,例如超过 八十个,则垂直分割该表,将原来的一个表分解为两个表。 (4) 对数据库管理系统DBMS进行系统优化,即优化各种系统参数,如缓冲区个数。 (5) 在使用面向数据的SQL语言进行程序设计时,尽量采取优化算法。 总之,要提高数据库的运行效率,必须从数据库系统级优化、数据库设计级优化、程序实现级优化 ,这三个层次上同时下功夫。 上述十四个技巧,是许多人在大量的数据库分析与设计实践中,逐步总结出来的。对于这些经验的 运用,读者不能生帮硬套,死记硬背,而要消化理解,实事求是,灵活掌握。并逐步做到:在应用中发 展,在发展中应用。","categories":[],"tags":[{"name":"转载","slug":"转载","permalink":"https://s.wangd1.top/tags/%E8%BD%AC%E8%BD%BD/"}],"author":"wangd1"},{"title":"Spring Boot JdbcTemplate多数据源","slug":"springboot/7_jdbc","date":"2020-09-05T02:12:15.000Z","updated":"2023-04-17T07:27:28.341Z","comments":true,"path":"archives/691.html","link":"","permalink":"https://s.wangd1.top/archives/691.html","excerpt":"Spring JdbcTemplate是spring对jdbc的封装,省去了自己管理数据库资源的麻烦,使得Jdbc更容易使用。Srping JdbcTemplate配置druid多数据源时,主要需要在创建JdbcTemplate时为其分配不同的数据源,在访问不同数据库的时候,使用不用的JdbcTemplate即可。","text":"Spring JdbcTemplate是spring对jdbc的封装,省去了自己管理数据库资源的麻烦,使得Jdbc更容易使用。Srping JdbcTemplate配置druid多数据源时,主要需要在创建JdbcTemplate时为其分配不同的数据源,在访问不同数据库的时候,使用不用的JdbcTemplate即可。 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.18</version></dependency> 配置多数据源 server: port: 8088spring: datasource: druid: #数据库访问配置 #数据源1 one: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8 username: root password: 8023love #数据源2 two: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test02?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8 username: root password: 8023love # 连接池配置 initial-size: 5 min-idle: 5 max-active: 20 # 连接等待超时时间 max-wait: 30000 # 配置检测可以关闭的空闲连接间隔时间 time-between-eviction-runs-millis: 60000 # 配置连接在池中的最小生存时间 min-evictable-idle-time-millis: 300000 validation-query: select '1' from dual test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true max-open-prepared-statements: 20 max-pool-prepared-statement-per-connection-size: 20 # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙 filters: stat,wall # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔 aop-patterns: com.wangd1.jdbc.servie.* # WebStatFilter配置 web-stat-filter: enabled: true # 添加过滤规则 url-pattern: /* # 忽略过滤的格式 exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' # StatViewServlet配置 stat-view-servlet: enabled: true # 访问路径为/druid时,跳转到StatViewServlet url-pattern: /druid/* # 是否能够重置数据 reset-enable: false # 需要账号密码才能访问控制台 login-username: druid login-password: druid123 # IP白名单 # allow: 127.0.0.1 # IP黑名单(共同存在时,deny优先于allow) # deny: 192.168.1.218 # 配置StatFilter filter: stat: log-slow-sql: true 创建一个数据源配置类; @Configurationpublic class DataSourceConfig { @Bean("dataSourceOne") @ConfigurationProperties("spring.datasource.druid.one") public DataSource mDataSourceOne(){ return DruidDataSourceBuilder.create().build(); } @Bean("dataSourceTwo") @ConfigurationProperties("spring.datasource.druid.two") public DataSource mDataSourceTwo(){ return DruidDataSourceBuilder.create().build(); } @Primary @Bean("jdbcTemplateOne") public JdbcTemplate mJdbcTemplateOne(@Qualifier("dataSourceOne") DataSource dataSource){ return new JdbcTemplate(dataSource); } @Bean("jdbcTemplateTwo") public JdbcTemplate mJdbcTemplateTwo(@Qualifier("dataSourceTwo") DataSource dataSource){ return new JdbcTemplate(dataSource); }} 上面创建了dataSourceOne和dataSourceOne两个数据源,并根据这两个数据源创建了两个jdbctemplate。 @Primary意思是如果有很多相同的bean,优先使用用了@Primary的bean。 配置多数据源的时候,势必有一个主数据源,不然在不使用@Qualifier(“jdbcTemplateOne”)注入jdbcTemplate的时候,会报错,因为会匹配到两个jdbcTemplate。 使用@Primary之后,可以不用@Qualifier注解,使用其他数据源的时候再使用@Qualifier。 测试 创建表并添加数据 test01.user: test02.user: 然后创建dao和service IUserOneDao: public interface IUserOneDao { List<Map<String,Object>> getAllUser();} 实现:注入了jdbcTemplateOne @Repositorypublic class UserOneDaoImpl implements IUserOneDao { @Autowired @Qualifier("jdbcTemplateOne") private JdbcTemplate mJdbcTemplate; @Override public List<Map<String, Object>> getAllUser() { return mJdbcTemplate.queryForList("select * from user"); }} IUserTwoDao: public interface IUserTwoDao { List<Map<String,Object>> getAllUser();} 实现:注入了jdbcTemplateTwo @Repositorypublic class UserTwoDaoImpl implements IUserTwoDao { @Autowired @Qualifier("jdbcTemplateTwo") private JdbcTemplate mJdbcTemplate; @Override public List<Map<String, Object>> getAllUser() { return mJdbcTemplate.queryForList("select * from user"); }} IUserService: public interface IUserService { List<Map<String,Object>> getAllUserFromOne(); List<Map<String,Object>> getAllUserFromTwo();} 实现: @Servicepublic class UserServiceImpl implements IUserService { @Autowired private IUserOneDao userOneDao; @Autowired private IUserTwoDao userTwoDao; @Override public List<Map<String, Object>> getAllUserFromOne() { return userOneDao.getAllUser(); } @Override public List<Map<String, Object>> getAllUserFromTwo() { return userTwoDao.getAllUser(); }} 然后UserController: @RestController@RequestMapping("/user")public class UserController { @Autowired private IUserService mUserService; @GetMapping("/allOne") public List<Map<String,Object>> getAllUserOne(){ return mUserService.getAllUserFromOne(); } @GetMapping("/allTwo") public List<Map<String,Object>> getAllUserTwo(){ return mUserService.getAllUserFromTwo(); }} 最后启动项目,访问 http://localhost:8088/user/allOne http://localhost:8088/user/allTwo 完","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"MySQL查询指定日期的数据","slug":"mysql/mysqlquery","date":"2020-07-27T16:00:00.000Z","updated":"2023-04-17T07:27:28.337Z","comments":true,"path":"archives/63302.html","link":"","permalink":"https://s.wangd1.top/archives/63302.html","excerpt":"记录下查询MySQL本周,上周,本月,最近N天的日期","text":"记录下查询MySQL本周,上周,本月,最近N天的日期 最近7天: -- 查询七天前的日期 -- 返回2020-07-21select DATE_SUB( CURDATE(), INTERVAL 7 DAY ) 最近15天: -- 查询十五天前的日期 -- 返回2020-07-13select DATE_SUB( CURDATE(), INTERVAL 15 DAY ) 最近1个月: -- 查询一个月前的日期 -- 返回2020-06-28select DATE_SUB( CURDATE(), INTERVAL 1 MONTH ) 最近一年: -- 查询一年前的日期 -- 返回2019-07-28select DATE_SUB( CURDATE(), INTERVAL 1 YEAR ) 查询本周: -- 查询当前日期是第多少周,因为我们一周从周一开始,所以需要设置参数1 -- 返回202031,表示第31周select YEARWEEK(DATE_FORMAT(CURDATE(),'%Y-%m-%d'),1) 查询上周: -- 查询上一周是第多少周,因为我们一周从周一开始,所以需要设置参数1 -- 获取七天前的日期,然后计算-- 返回202030,表示第30周select YEARWEEK(DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 7 DAY),'%Y-%m-%d'),1) 查询本月: -- 查询本月,就格式化select DATE_FORMAT(CURDATE(), '%Y%m') 查询周一到周五: -- 减1是周一,以此类推-- 返回2020-07-27周一select SUBDATE(CURDATE(),DATE_FORMAT(CURDATE(),'%w')-1)-- 返回2020-07-27周二select SUBDATE(CURDATE(),DATE_FORMAT(CURDATE(),'%w')-2) 查询指定日期:就直接比较","categories":[],"tags":[{"name":"MySQL","slug":"MySQL","permalink":"https://s.wangd1.top/tags/MySQL/"}],"author":"wangd1"},{"title":"Spring Boot Mybatis(注解)、多数据源","slug":"springboot/6_mybatis","date":"2019-10-18T12:12:15.000Z","updated":"2023-04-17T07:27:28.340Z","comments":true,"path":"archives/58111.html","link":"","permalink":"https://s.wangd1.top/archives/58111.html","excerpt":"SpringBoot整合Mybatis创建工程,添加依赖<!--连接池--><dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><!--Mybatis--><dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version></dependency> <!--MySql驱动--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency>","text":"SpringBoot整合Mybatis创建工程,添加依赖<!--连接池--><dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><!--Mybatis--><dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version></dependency> <!--MySql驱动--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency> 配置属性文件spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test01?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMTspring.datasource.username=rootspring.datasource.password=rootspring.datasource.type=com.alibaba.druid.pool.DruidDataSource 添加一些注解配置完成后,就可以编写一些Mapper,并搭配注解使用了 public interface UserMapper { @Select("select * from user") List<User> getAll(); @Results({ @Result(property = "id", column = "id"), @Result(property = "username" , column = "name"), @Result(property = "address" , column = "a") }) @Select("select id as id, username as u,address as a from user where id=#{id}") User get(Long id); @Select("select * from user where username like concat('%',#{name},'%')") List<User> getByName(String name); @Insert({"insert into user(username,address) values(#{username},#{address})"}) @SelectKey(statement = "select last_insert_id()", keyProperty = "id", before = false, resultType = Long.class) Integer add(User user); @Update("update user set username=#{username},address=#{address} where id=#{id}") Integer update(User user); @Delete("delete from user where id=#{id}") Integer delete(Long id);} 使用注解来写SQL,和XML方式都可以对应上,@Select,@Insert,@Update,@Delete就分别对应、、、,@Results注解类似于XML中的ResultMap映射文件,@SelectKey注解可以实现主键回填的功能,即当数据插入成功后,插入成功的数据id会赋值到user对象的id属性上。 另外还需要配置注解扫描,在Mapper类上使用@Mapper或者在启动类前加上@MapperScan(basePackages = “com.wd.m.mapper”)注解,指定Mapper类所在路径。 测试在单元测试中注入UserMapper,然后编写测试类测试。 User user = new User();user.setUsername("wangd1").setAddress("安徽合肥");Integer isInsert = userMapper.add(user);System.out.println(isInsert);System.out.println(user); SpringBoot整合Mybatis多数据源:依然创建工程,添加依赖,和上面一样<!--连接池--><dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><!--Mybatis--><dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version></dependency><!--MySql驱动--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency> 配置多数据源多加一个数据源: spring.datasource.one.url=jdbc:mysql://127.0.0.1:3306/test01?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMTspring.datasource.one.username=rootspring.datasource.one.password=rootspring.datasource.one.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.two.url=jdbc:mysql://127.0.0.1:3306/test02?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMTspring.datasource.two.username=rootspring.datasource.two.password=rootspring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource 提供两个DataSource: @Configurationpublic class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.one") DataSource dsOne(){ return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.two") DataSource dsTwo(){ return DruidDataSourceBuilder.create().build(); }} 添加两个Mybatis配置类: 创建MyBatisConfigOne类,首先指明该类是一个配置类,配置类中要扫描的包是com.wd.springboot07mybatis.mapper,即该包下的Mapper接口将操作dsOne中的数据,对应的SqlSessionFactory和SqlSessionTemplate分别是sqlSessionFactory1和sqlSessionTemplate1,在MyBatisConfigOne内部,分别提供SqlSessionFactory和SqlSessionTemplate即可,SqlSessionFactory根据dsOne创建,然后再根据创建好的SqlSessionFactory创建一个SqlSessionTemplate。 @Configuration@MapperScan(basePackages = "com.wd.springboot07mybatis.mapper",sqlSessionFactoryRef = "sqlSessionFactory1",sqlSessionTemplateRef = "sqlSessionTemplate1")public class MyBatisConfigOne { @Resource(name = "dsOne") DataSource dsOne; @Bean SqlSessionFactory sqlSessionFactory1() { SqlSessionFactory sessionFactory = null; try { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dsOne); sessionFactory = bean.getObject(); } catch (Exception e) { e.printStackTrace(); } return sessionFactory; } @Bean SqlSessionTemplate sqlSessionTemplate1() { return new SqlSessionTemplate(sqlSessionFactory1()); }} @Configuration@MapperScan(basePackages = "com.wd.springboot07mybatis.mapper2",sqlSessionFactoryRef = "sqlSessionFactory2",sqlSessionTemplateRef = "sqlSessionTemplate2")public class MyBatisConfigTwo { @Resource(name = "dsTwo") DataSource dsTwo; @Bean SqlSessionFactory sqlSessionFactory2() { SqlSessionFactory sessionFactory = null; try { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dsTwo); sessionFactory = bean.getObject(); } catch (Exception e) { e.printStackTrace(); } return sessionFactory; } @Bean SqlSessionTemplate sqlSessionTemplate2() { return new SqlSessionTemplate(sqlSessionFactory2()); }} 然后可以创建两个Mapper包,mapper和mapper2 然后测试:通过注入不同的Mapper,就可以操作不同的数据源: @Autowiredprivate UserMapper2 userMapper2;@Autowiredprivate UserMapper userMapper;@Testvoid contextLoads() { User user = new User(); user.setUsername("wangd1").setAddress("安徽合肥"); Integer isInsert = userMapper2.add(user); System.out.println(isInsert); System.out.println(user); } 另外多数据源的整合也可以通过AOP实现,有空再研究一下","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot Springboot整合Swagger2","slug":"springboot/5_swagger2","date":"2019-10-14T13:10:11.000Z","updated":"2023-04-17T07:27:28.340Z","comments":true,"path":"archives/19684.html","link":"","permalink":"https://s.wangd1.top/archives/19684.html","excerpt":"SpringBoot整合Swagger2swagger2 是一个规范和完整的框架,用于生成、描述、调用和可视化Restful风格的web服务: 接口文档在线自动生成,文档随接口变动实时更新,节省维护成本 支持在线接口测试,不依赖第三方工具 更可以大大的减少沟通成本。","text":"SpringBoot整合Swagger2swagger2 是一个规范和完整的框架,用于生成、描述、调用和可视化Restful风格的web服务: 接口文档在线自动生成,文档随接口变动实时更新,节省维护成本 支持在线接口测试,不依赖第三方工具 更可以大大的减少沟通成本。 创建项目,添加相关依赖<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency> 配置Swagger2创建一个Swagger2的配置类: @Configuration@EnableSwagger2public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .pathMapping("/") .select() .apis(RequestHandlerSelectors.basePackage("com.wd.springboot09swagger2.controller")) .paths(PathSelectors.any()) .build().apiInfo(new ApiInfoBuilder() .title("SpringBoot整合Swagger2") .description("SpringBoot整合Swagger") .version("1.0") .contact(new Contact("Contact","http://wangd1.com","[email protected]")) .license("The Apache License") .licenseUrl("http://www.baidu.com") .build()); }} 使用@EnableSwagger2注解启用Swagger2,然后配置一个Bean,在这个Bean中,配置映射路径和要扫描的接口的位置,然后配置一下Swagger2文档网站的信息ApiInfo,例如网站的title,网站的描述,联系人的信息,使用的协议等等。 然后启动项目,输入http://localhost:8080/swagger-ui.html看到以下页面就成功了。 创建接口配置完成后,就可以编写一些接口 @RestController@Api(tags = "用户管理相关接口")@RequestMapping("/user")public class UserController { @PostMapping("/") @ApiOperation("添加用户的接口") @ApiImplicitParams({ @ApiImplicitParam(name = "username", value = "姓名", defaultValue = "wangd1"), @ApiImplicitParam(name = "address", value = "地址", defaultValue = "合肥", required = true)} ) public ResponseBean addUser(String username, @RequestParam(required = true) String address) { System.out.println(username); System.out.println(address); return new ResponseBean(); } @GetMapping("/") @ApiOperation("根据id查询用户的接口") @ApiImplicitParam(name = "id", value = "用户id", defaultValue = "99", required = true) public User getUserById(@PathVariable Long id) { User user = new User(); user.setId(id); return user; } @PutMapping("/{id}") @ApiOperation("根据id更新用户的接口") public User updateUserById(@RequestBody User user) { return user; }} 其中 @Api表明接口的作用, @ApiOperation表明方法的作用 @ApiImplicitParam用来配置方法参数的一些含义,也可以设置默认值,如果有多个参数,需要将其放在@ApiImplicitParams注解中。 另外是@ApiImplicitParam中的required仅对swagger2框架有用,脱离了就没用了。所以@RequestParam(required = true)最好不要省略。 配置完后,重启,打开刚刚的页面,可以看到: 一目了然,并且可以通过右上角的Try it out来测试接口。 swagger-ui.html 中导出的API文件可以在 Swagger Editor(http://editor.swagger.io/) 中打开","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot Thymeleaf","slug":"springboot/4_thymeleaf","date":"2019-07-04T12:12:15.000Z","updated":"2023-04-17T07:27:28.340Z","comments":true,"path":"archives/63984.html","link":"","permalink":"https://s.wangd1.top/archives/63984.html","excerpt":"Thymeleaf介绍 Thymeleaf是现代化服务器端的Java模板引擎,不同与其它几种模板的是Thymeleaf的语法更加接近HTML,并且具有很高的扩展性。详细资料可以浏览官网。 支持无网络环境下运行,可直接运行,这样会加载默认的数据。如果数据返回到页面时,Thymeleaf的标签会动态替换掉静态内容。 SpringBoot官方推荐模板,提供了可选集成模块(spring-boot-starter-thymeleaf),可以快速的实现表单绑定、属性编辑器、国际化等功能。","text":"Thymeleaf介绍 Thymeleaf是现代化服务器端的Java模板引擎,不同与其它几种模板的是Thymeleaf的语法更加接近HTML,并且具有很高的扩展性。详细资料可以浏览官网。 支持无网络环境下运行,可直接运行,这样会加载默认的数据。如果数据返回到页面时,Thymeleaf的标签会动态替换掉静态内容。 SpringBoot官方推荐模板,提供了可选集成模块(spring-boot-starter-thymeleaf),可以快速的实现表单绑定、属性编辑器、国际化等功能。 Thymeleaf简单使用首先创建一个springboot web项目。 然后在pom.xml文件中添加对 thymeleaf 的依赖: <!--引入thymeleaf--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency> 可以在properties文件中对thymeleaf配置,配置项可以在ThymeleafProperties.class文件中找到: @ConfigurationProperties( prefix = "spring.thymeleaf")public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; private boolean checkTemplate = true; private boolean checkTemplateLocation = true; private String prefix = "classpath:/templates/"; private String suffix = ".html"; private String mode = "HTML"; private Charset encoding; private boolean cache; ... ...} 创建一个ThymeleafController.java和templates/welcome.html ThymeleafController: @GetMapping("/hello")public String hello(Map<String,Object> map){ map.put("hello","hello thymeleaf"); return "welcome";} welcome.html: 加入 <html lang="en" xmlns:th="http://www.thymeleaf.org">会有语法提示。 <!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h1>Welcome</h1> <p th:text="${hello}">你好</p></body></html> 运行,浏览器输入 http://localhost:8085/hello可以看到效果: 如果直接运行这个html,则会显示默认值: Thymeleaf语法可以参考 https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot Web 静态资源的映射规则","slug":"springboot/webstatic","date":"2019-07-03T14:12:15.000Z","updated":"2023-04-17T07:27:28.341Z","comments":true,"path":"archives/60776.html","link":"","permalink":"https://s.wangd1.top/archives/60776.html","excerpt":"","text":"SpringBoot对静态资源的映射规则 所有/webjars/**,都去classpath:/META-INFO/resources/webjars找资源; webjars:以jar包的形式引入静态资源。(https://www.webjars.org/) <!--引用jquery的webjars--><dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.4.1</version></dependency> 访问:http://localhost:8085/webjars/jquery/3.4.1/jquery.js “/**” 访问当前项目的任何资源(静态资源文件夹) “classpath:/META_INFO/resources/“, “classpath:/resources/“, “classpath:/static/“, “classpath:/public/“, “/“:当前项目的根路径, 欢迎页:静态资源文件夹下的所有index.html 图标:静态资源文件夹下的favorite.ico 修改静态资源文件夹路径: spring.resources.static-locations=classpath:/hello/,classpath:/abc/","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot 日志配置","slug":"springboot/3_logging","date":"2019-07-03T12:12:15.000Z","updated":"2023-04-17T07:27:28.339Z","comments":true,"path":"archives/54485.html","link":"","permalink":"https://s.wangd1.top/archives/54485.html","excerpt":"常见的框架日志有:log4j,log4j2,logback,common-logging(JCL),java-util-logging(JUL)和slf4j等。 而日志框架主要分两类: 日志门面(抽象)如:jboss-logging,slf4j,JCL 日志实现(实现)如:log4j,log4j2,logback,JUL 对于日志实现,JUL实现简陋,很多地方被开发者吐槽,所以排除;log4j和logback是同一个作者开发的,且logback是log4j的升级版,比log4j会更好点,排除log4j;log4j2不是log4j的升级版,因为太过于优秀,部分框架对其的支持有限,所以排除。 所以日志实现选中logback。 对于日志门面,jboss-logging很久未更新,而slf4j的作者就是log4j和logback的作者,所以选用slf4j和logback会比较合得来…. 所以日志门面选用slf4j。并且在springboot中也是使用的 slf4j + logback。","text":"常见的框架日志有:log4j,log4j2,logback,common-logging(JCL),java-util-logging(JUL)和slf4j等。 而日志框架主要分两类: 日志门面(抽象)如:jboss-logging,slf4j,JCL 日志实现(实现)如:log4j,log4j2,logback,JUL 对于日志实现,JUL实现简陋,很多地方被开发者吐槽,所以排除;log4j和logback是同一个作者开发的,且logback是log4j的升级版,比log4j会更好点,排除log4j;log4j2不是log4j的升级版,因为太过于优秀,部分框架对其的支持有限,所以排除。 所以日志实现选中logback。 对于日志门面,jboss-logging很久未更新,而slf4j的作者就是log4j和logback的作者,所以选用slf4j和logback会比较合得来…. 所以日志门面选用slf4j。并且在springboot中也是使用的 slf4j + logback。 简单使用首先导入slf4j的jar包和logback的jar包 在开发的时候,日志记录方法的调用不应该直接调用日志的实现类,而是调用日志抽象层里面的方法。 参考官方文档:https://www.slf4j.org/manual.html import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class HelloWorld { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(HelloWorld.class); logger.info("Hello World"); }} 如何让系统中的所有的日志都统一到slf4j在系统中,自己使用了slf4j+logback,但是Spring默认的是commons-logging;如果集成Hibernate,他又自带了jboss-logging;如果集成mybatis,他又有自己的日志系统。 想统一日志框架,都使用slf4j输出日志,可以参考slf4j官网 https://www.slf4j.org/legacy.html slf4j提供了解决方案: 将系统中的其他日志框架排除出去(删除其他日志框架的jar包,如:commons-logging日志的jar包等); 然后使用中间包来替代原有的日志框架(如上图的jcl-over-slf4j.jar replaces commons-logging.jar,log4j-over-slf4j.jar replaces log4j.jar等); 导入slf4j其他日志包的实现; 那些中间包实际上提供了原有包的功能,但是也对slf4j进行了实现。就像log4j-to-slf4j.jar下面的路径还是和log4j一样,但是里面的日志记录的功能使用的是slf4j: Spring Boot的日志关系新建一个springboot项目,然后打开pom文件,查看依赖(右键>Diagrams>Show…) 看到SpringBoot依赖spring-boot-starter <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.1.7.RELEASE</version> <scope>compile</scope></dependency> 而spring-boot-starter依赖spring-boot-starter-logging,所以springboot使用它来做日志功能。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>2.1.7.RELEASE</version> <scope>compile</scope></dependency> 看一下spring-boot-starter-logging: 所以springboot底层是使用slf4j+logback的方式进行日志记录的,并把其他日志替换成了slf4j; 使用和配置 修改日志级别 import org.junit.Test;import org.junit.runner.RunWith;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTestpublic class SpringBoot03LoggingApplicationTests { Logger logger = LoggerFactory.getLogger(SpringBoot03LoggingApplicationTests.class); @Test public void contextLoads() { //日记级别: //从低到高:trace<debug<info<warn<error //可以调整输出的日志级别;日志就只在这个级别和之后的高级别生效 logger.trace("这是trace日志"); logger.debug("这是debug日志"); //调试日志 //springboot默认的日志级别是info,所以运行时只会打印info级别和高于info级别的日志信息 logger.info("这是info日志"); // logger.warn("这是warn日志"); //警告日志 logger.error("这是error日志"); //错误日志 }} 所以打印是: 但是可以通过properties等配置文件修改日志级别: logging.level.com.wangd = trace 修改指定位置文件的日志级别后打印如下: 生成日志文件 指定logging.file logging.level.com.wangd = trace# 不指定路径和文件的情况下,只在控制台打印日志信息# 若指定了logging.file,而无论是否指定logging.path,都只在指定文件中保存日志信息,而不会在路径中保存日志# 对于logging.path,若指定了目录,则会在这个目录中自动生成spring.log保存日志信息#logging.path=/spring/loglogging.file=spring.log 指定logging.path=/spring/log logging.level.com.wangd = trace# 不指定路径和文件的情况下,只在控制台打印日志信息# 若指定了logging.file,而无论是否指定logging.path,都只在指定文件中保存日志信息,而不会在路径中保存日志# 对于logging.path,若指定了目录,则会在当前磁盘的这个目录中自动生成spring.log保存日志信息logging.path=/spring/log#logging.file=spring.log 修改日志输出格式 # 日志输出格式:# %d:日期时间# %thread:线程名# %-5level:级别从左显示5个字符宽度# %logger{50}:表示logger名字最长50个字符,否则按照句点切割# %msg:日志消息# %n:换行符# 在控制台输出日志的格式logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-2level %logger{5} - %msg%n# 在日志文件中输出日志的格式logging.pattern.file=%d{yyyy-MM-dd} === [%thread] %-5level %logger{50} - %msg%n 使用@Slf4j注解 在使用类名的时候,每个类都需要自己编写 Logger mLogger = LoggerFactory.getLogger(XXX.class); 会很不方便,所以可以通过一个注解(@Slf4j)来帮我们实现,该注解就可以帮我们自动创建一个 log对象。 但是 如果使用 @Slf4j 注解 需要两点, 安装lombok插件,参考idea安装插件 添加 lombok的依赖 <!--添加lombok依赖--><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId></dependency> 就可以使用@Slf4j注解了。 @RunWith(SpringRunner.class)@SpringBootTest@Slf4jpublic class SpringBoot03LoggingApplicationTests { @Test public void contextLoads() { log.info("这是info日志"); // log.warn("这是warn日志"); //警告日志 log.error("这是error日志"); //错误日志 }} 指定日志配置文件 logback.xml可以被日志框架直接识别; logback-spring.xml无法被日志框架识别,但是可以由springboot识别,可以使用springboot的高级Profile功能。 <!-- 如在logback-spring.xml中加入--><springProfile name="dev"> <!-- 可以指定某段配置只在某个环境下生效--> <pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %level [%thread] [%logger{100}.%method:%line] - %msg%n</pattern></springProfile>,<!--然后修改properties配置文件的profile为dev-->spring.profiles.active=dev就可以在启动环境为dev时,日志打印的格式为对应配置的格式 所以logback[-spring].xml,格式需要自己查询。 另外logback.xml文件中配置了springProfile的话,运行会报错。 <?xml version="1.0" encoding="utf-8" ?><configuration> <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender"> <springProfile name="dev"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d -- %msg%n</pattern> </layout> </springProfile> <springProfile name="test"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d -----== %msg%n</pattern> </layout> </springProfile> </appender> <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!--要拦截的日志级别--> <level>ERROR</level> <!--如果匹配,则禁止--> <onMatch>DENY</onMatch> <!--如果不匹配,则允许记录--> <onMismatch>ACCEPT</onMismatch> </filter> <encoder> <pattern>%d -- %msg%n</pattern> </encoder> <!--滚动策略--> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--路径--> <fileNamePattern>d:/info-%d.log</fileNamePattern> </rollingPolicy> </appender> <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--添加 范围 过滤--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> <encoder> <pattern>%d -- %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>d:/error-%d.log</fileNamePattern> </rollingPolicy> </appender> <root level="info"> <appender-ref ref="consoleLog" /> <appender-ref ref="fileInfoLog"/> <appender-ref ref="fileErrorLog"/> </root></configuration>","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot 配置文件2","slug":"springboot/2_config2","date":"2019-07-02T13:12:15.000Z","updated":"2023-04-17T07:27:28.339Z","comments":true,"path":"archives/61133.html","link":"","permalink":"https://s.wangd1.top/archives/61133.html","excerpt":"对于@ConfigurationProperties注解默认加载全局的配置文件,但是如果所有的配置信息都写在全局的配置文件中就会很臃肿,所以需要自定义配置文件和使用@PropertiesSource注解来加载指定的配置文件。","text":"对于@ConfigurationProperties注解默认加载全局的配置文件,但是如果所有的配置信息都写在全局的配置文件中就会很臃肿,所以需要自定义配置文件和使用@PropertiesSource注解来加载指定的配置文件。 @PropertiesSource:加载指定的配置文件自定义一个配置文件person.properties person.lastName=叶秋person.age=19person.birth=2019/10/1person.boss=trueperson.maps.k1=v1person.maps.k2=v2person.lists=a,b,cperson.dog.name=dogperson.dog.age=2 加上@PropertiesSource注解 @Component@PropertySource(value = "classpath:person.properties")@ConfigurationProperties(prefix = "person")//@Validatedpublic class Person { private String lastName; ... get set toString()} 依然运行单元测试 @RunWith(SpringRunner.class)@SpringBootTestpublic class SpringBoot02ConfigApplicationTests { @Autowired Person mPerson; @Test public void contextLoads() { System.out.println(mPerson); }} 可以看到结果: 同时: @PropertySource(value = “classpath:person.properties”) @ConfigurationProperties(prefix = “person”) 这两个注解都要加上,并且优先加载全局配置文件信息,当在全局配置文件中不存在时,才会加载自定义的配置文件。 优先级:properties > yml > 自定义的配置文件 @ImportResource:导入Spring的配置文件Spring Boot中没有Spring的配置文件,自己编写的配置文件无法自动识别,所以需要在配置类上使用@ImportResource注解让配置文件生效。 比如创建一个HelloService类,编写beans.xml配置文件: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="com.wangd.springboot02config.service.HelloService"></bean></beans> 想让这个bean加载进容器中,就需要@ImportResource注解: @ImportResource(value = "classpath:beans.xml")@SpringBootApplicationpublic class SpringBoot02ConfigApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot02ConfigApplication.class, args); }} 然后运行单元测试可以看到结果: @AutowiredApplicationContext ioc;@Testpublic void testHelloService(){ System.out.println(ioc.containsBean("helloService"));} @Configuration但是SpringBoot推荐的给容器添加组件的方式是使用全注解的方式:使用@Configuration和@Bean注解。 添加一个配置类,加上相应的注解: /** * @Configuration 注解表明当前类是一个配置类,来代替之前的Spring的配置文件xml */@Configurationpublic class MyAppConfig { //@Bean:将方法的返回值添加到容器中,id就是方法名 @Bean public HelloService helloService(){ return new HelloService(); }} 然后将之前@ImportResource注解注释,运行测试方法(testHelloService)可以看到: 其他配置1. ProfileProfile是Spring对不同环境提供不同配置功能的支持,可以通过激活,指定参数等方式快速切换环境。 格式是:application-{profile}.properties 多Profile文件 在主配置文件编写的时候,文件名可以是application-{profile}.properties/yml 假如创建了三个properties/yml文件,文件名分别是 application-dev.properties server.port=8081 application-test.properties server.port=8082 application.properties(默认) server.port=8088 直接启动,会启动默认配置文件,端口为8088; 可以使用 spring.profiles.active=dev 来配置启动不同的配置文件,如上启动端口为8081。 多文档块 在yml中使用’—‘可以划分文档块 server: port: 8088spring: profiles: active: dev---server: port: 8089spring: profiles: dev---server: port: 8082spring: profiles: test #指定属于哪个环境 需要把properties中的端口注释掉,才可以看到效果 激活指定profile的方式 在配置文件中指定:spring.profiles.active=dev 命令行指定:java -jar xxx.jar –spring.profiles.active=dev 虚拟机参数:**-Dspring:profiles.active=dev** 2. 配置文件加载位置Spring Boot启动会扫描以下位置的application.properties/.yml文件作为默认配置文件: file:./config file:./ classpath:./config classpath:./ 以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,并互补配置,即高优先级配置内容会覆盖低优先级配置内容,且高优先级没有但低优先级有的配置依然生效。 如:最高级别的端口8085,低级别的端口8087,且多了个server.servlet.context-path 然后自行编写一个HelloControler,启动项目后,端口是8085,但是访问http://localhost:8085/hello会报错,访问http://localhost:8085/boot/hello才正常,这就是互补配置。 也可以通过spring.config.location来改变默认位置:项目打包后,可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置,并且指定配置文件和默认加载的配置文件共同起作用,形成互补配置 3. 外部文件加载顺序(官方文档)https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#boot-features-external-config,按照级别从高到低,互补配置。","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot 配置文件1","slug":"springboot/2_config1","date":"2019-07-02T12:12:15.000Z","updated":"2023-04-17T07:27:28.338Z","comments":true,"path":"archives/61325.html","link":"","permalink":"https://s.wangd1.top/archives/61325.html","excerpt":"Spring Boot 使用一个全局的配置文件,文件名是固定的:application.properties或application.yml。配置文件要是想被Spring Boot自动加载,需要放置到指定的位置:src/main/resource目录下,一般自定义的配置文件也位于此目录之下。","text":"Spring Boot 使用一个全局的配置文件,文件名是固定的:application.properties或application.yml。配置文件要是想被Spring Boot自动加载,需要放置到指定的位置:src/main/resource目录下,一般自定义的配置文件也位于此目录之下。 优先级:properties > yml 配置文件的作用是:修改Spring Boot的自动配置的默认值。 1. properties 文件格式server.port=8088person.last-name=zhangsnaperson.age=19person.birth=2019/10/1person.boss=trueperson.maps.k1=v1person.maps.k2=v2person.lists=a,b,cperson.dog.name=dogperson.dog.age=2 2. yml文件格式基本语法 K:(空格必须有)V(表示一个键值对,并且属性和值大小写敏感) 以空格的缩进来控制层级关系;只要是左对齐的一列数据,都是一个层级的。 如下: server: port: 8088 值的写法 字面量:普通的值(数字,字符串,布尔) 值可以直接来写,且字符串不用加引号; 如果加引号: name0: "zhangsan \\n lisi" #使用双引号会输出 zhangsan 换行 lisiname1: 'zhangsan \\n lisi' #使用单引号会输出 zhangsan \\n lisi 对象、Map: 键值对写法,如 person: lastName: zhangsan age: 20 行内写法,如 maps: {k1: v1,k2: v2} 数组(List等): 用换横线(-)表示一个数组元素,如 lists: - lisi - wangwu - zhaoliu 行内写法,如 lists: [lisi,wangwu,zhaoliu] 演示 server: port: 8088person: lastName: zhangsan age: 20 boss: true birth: 2019/10/1 maps: {k1: v1,k2: v2} lists: - lisi - wangwu - zhaoliu dog: name: 笨笨 age: 2 3. 获取配置文件的值(@ConfigurationProperties和@Component方式)创建了一个Person类和Dog类,加入@ConfigurationProperties和@Component注解 /** * 将配置文件中配置的每一个属性的值,映射到这个组件中, * @ConfigurationProperties 是告诉SpringBoot将本类中的所有属性和配置文件中的相关配置进行绑定 * prefix = "person" 与配置文件中那个下面的属性进行一一映射 * * 只有这个组件是容器的中的组件,才可以使用这个@ConfigurationProperties注解的功能 */@Component@ConfigurationProperties(prefix = "person")public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String,Object> maps; private List<Object> lists; private Dog dog; ...get set toString()}public class Dog { private String name; private Integer age; ...get set toString()} 加入提供的maven依赖,可以在编写yml文件时有提示。 <!-- 导入配置文件处理器,配置文件进行绑定时会有提示--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional></dependency> 然后编写单元测试,注入Person,然后打印配置文件里的值; @RunWith(SpringRunner.class)@SpringBootTestpublic class SpringBoot02ConfigApplicationTests { @Autowired Person mPerson; @Test public void contextLoads() { System.out.println(mPerson); }} 运行单元测试可以看到结果: 如果使用的是properties文件且有中文的话,打印出来会乱码(idea的properties配置文件编码是utf-8),需要配置一下就不会乱码了。 4. 获取配置文件的值(@Value方式)@Value可以获取的值有 字面量(字符串等)、**${key}(从环境变量、配置文件中获取值)、#{SpEL}** 如: @Component//@ConfigurationProperties(prefix = "person")public class Person { @Value("${person.lastName}") private String lastName; @Value("#{10+10}") private Integer age; @Value("false") private Boolean boss; ...} 打印 5. @Value获取值和@ConfigurationProperties获取值比较 @Value @ConfigurationProperties 功能 需一个一个指定 可批量注入配置文件的属性 松散绑定(松散语法,如下) 不支持(@Value里的值要与配置文件中的一致或是使用配置文件里提示的值) 支持 SpEL 支持 不支持(配置文件中不支持表达式) JSP303数据校验(如@Validated,@Email) 不支持 支持 复杂类型封装(Map) 不支持 支持 属性名匹配规则 person.lastName:标准方式 person.last-name:大写用- person.last_name:大写用_ PERSON_LAST_NAME 配置文件是yml或properties都可以获取到值。 所以, 如果说只是在某个业务逻辑中需要用到配置文件中的某项值,用@Value比较灵活 如果说专门写了一个javaBean来和配置文件相映射,就直接使用@ConfigurationProperties 未完…","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"Spring Boot HelloWorld","slug":"springboot/1_helloworld","date":"2019-07-01T13:12:15.000Z","updated":"2023-04-17T07:27:28.338Z","comments":true,"path":"archives/46241.html","link":"","permalink":"https://s.wangd1.top/archives/46241.html","excerpt":"1.简介Spring Boot的设计目的就是简化Spring应用的开发,开启了各种自动装配,约定大于配置,去繁从简,引入相关的依赖就可以迅速搭建起一个web工程。","text":"1.简介Spring Boot的设计目的就是简化Spring应用的开发,开启了各种自动装配,约定大于配置,去繁从简,引入相关的依赖就可以迅速搭建起一个web工程。 优点快速创建独立运行的Spring项目以及与主流框架集成使用嵌入式的Servlet容器,应用无需打成war包starters自动依赖与版本控制大量的自动配置,简化开发,也可以修改默认值无需配置XML文件,无代码生成,开箱即用准生产环境的运行时应用监控与云计算天然集成2.构建工程使用IDEA构建Spring Boot工程打开IDEA,File->New Project/New Module->Spring Initializr,下一步,填写好Group,Artifact,下一步,勾选Spring Web Starter开启web功能,然后输入项目名称,Finish。 工程目录(controller是自己创建的) 其中: pom 文件为基本的依赖管理文件resouces 资源文件statics 静态资源templates 模板资源application.yml / application.properties 配置文件SpringbootXXXApplication 程序的入口。 演示创建一个controller @RestControllerpublic class HelloController { @GetMapping("/hello") public String hello(){ return "hello world"; }} 其中 @RestController 是 @ResponseBody和@Controller两个注解的结合,表示方法返回的数据直接写给浏览器,如果是对象就转为json数据。 @GetMapping 注解就是@RequestMapping(method = RequestMethod.GET)注解的缩写 然后启动SpringBoot01HelloworldApplication的main方法,在浏览器输入localhost:8080/hello 打包点击IDEA工程的右侧 Maven Project,找到对应项目,依次执行clean,package 可以看到jar包路径 命令行定位到jar包目录,执行java -jar xxx.jar,然后在浏览器输入localhost:8080/hello可以看到同样效果","categories":[],"tags":[{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"}],"author":"wangd1"},{"title":"晨雾","slug":"雾","date":"2019-03-07T16:00:00.000Z","updated":"2023-04-17T07:27:28.342Z","comments":true,"path":"archives/52752.html","link":"","permalink":"https://s.wangd1.top/archives/52752.html","excerpt":"前两天拍的清晨的大雾,能见度很低,给人一种窒息感。但是站在高处看有种仙境的感觉,而且,大雾之后,是万里无云的蓝天,也算是给阴雨许多天的合肥一个不错的交代了。","text":"前两天拍的清晨的大雾,能见度很低,给人一种窒息感。但是站在高处看有种仙境的感觉,而且,大雾之后,是万里无云的蓝天,也算是给阴雨许多天的合肥一个不错的交代了。","categories":[],"tags":[{"name":"随想","slug":"随想","permalink":"https://s.wangd1.top/tags/%E9%9A%8F%E6%83%B3/"},{"name":"生活","slug":"生活","permalink":"https://s.wangd1.top/tags/%E7%94%9F%E6%B4%BB/"}],"author":"wangd1"},{"title":"乌镇","slug":"乌镇行","date":"2018-12-18T13:12:15.000Z","updated":"2023-04-17T07:27:28.341Z","comments":true,"path":"archives/26974.html","link":"","permalink":"https://s.wangd1.top/archives/26974.html","excerpt":"乌镇行","text":"乌镇行","categories":[],"tags":[{"name":"随想","slug":"随想","permalink":"https://s.wangd1.top/tags/%E9%9A%8F%E6%83%B3/"},{"name":"生活","slug":"生活","permalink":"https://s.wangd1.top/tags/%E7%94%9F%E6%B4%BB/"}],"author":"wangd1"},{"title":"冬","slug":"冬","date":"2018-11-07T14:16:01.000Z","updated":"2023-04-17T07:27:28.341Z","comments":true,"path":"archives/60019.html","link":"","permalink":"https://s.wangd1.top/archives/60019.html","excerpt":"冬将至","text":"冬将至","categories":[],"tags":[{"name":"随想","slug":"随想","permalink":"https://s.wangd1.top/tags/%E9%9A%8F%E6%83%B3/"}],"author":"wangd1"}],"categories":[],"tags":[{"name":"转载","slug":"转载","permalink":"https://s.wangd1.top/tags/%E8%BD%AC%E8%BD%BD/"},{"name":"Spring Boot","slug":"Spring-Boot","permalink":"https://s.wangd1.top/tags/Spring-Boot/"},{"name":"MySQL","slug":"MySQL","permalink":"https://s.wangd1.top/tags/MySQL/"},{"name":"随想","slug":"随想","permalink":"https://s.wangd1.top/tags/%E9%9A%8F%E6%83%B3/"},{"name":"生活","slug":"生活","permalink":"https://s.wangd1.top/tags/%E7%94%9F%E6%B4%BB/"}]}