Compare commits

...

22 Commits

Author SHA1 Message Date
7e650a0a04 修改版本号 2020-12-26 22:27:51 +08:00
45c59ecc37 前端新增深色主题模版 2020-12-26 22:16:58 +08:00
5e3962fef4 update 2020-12-26 20:10:11 +08:00
7f5035e369 update 2020-12-26 20:08:07 +08:00
44aad39847 update 2020-12-26 20:00:21 +08:00
6ad51908d5 文件夹结构调整,新增模版自定义功能 2020-12-26 19:13:07 +08:00
f03ab953d0 v3.2.0发布 2020-12-26 11:45:19 +08:00
5cc9dfa1bc v3.2.0发布 2020-12-26 11:42:09 +08:00
2fbda60617 修复jwt校验失败后的bug 2020-12-24 17:13:36 +08:00
39c19ac004 页面不存在则跳转到404页面 2020-12-24 16:54:37 +08:00
7494fe431a 页面不存在则跳转到404页面 2020-12-24 16:45:48 +08:00
c9f1500976 新增404页面,访问已删除的书页/目录页/内容页自动跳转到404页面 2020-12-24 16:26:21 +08:00
f61c252e71 爬虫代码优化 2020-12-24 01:30:00 +08:00
6fd183c2ae 爬虫代码优化 2020-12-24 01:22:19 +08:00
c3daaecaaa 爬虫代码优化 2020-12-24 01:17:52 +08:00
1b6cc8ccd5 爬虫代码优化 2020-12-24 00:10:19 +08:00
0a10504461 优化章节字数算法,优化爬虫代码 2020-12-23 23:48:34 +08:00
1046a7ffc1 后台数据校验优化 2020-12-22 23:12:22 +08:00
612555dbe6 更新QQ群 2020-12-22 09:35:24 +08:00
d5768e4011 后台首页gitee仓库地址更新 2020-12-21 17:51:54 +08:00
5982eb623f 更新文档 2020-12-16 09:53:39 +08:00
85ad5fa3b2 增加官网地址 2020-12-15 10:23:12 +08:00
1039 changed files with 119278 additions and 286 deletions

View File

@ -2,6 +2,10 @@
# 小说精品屋-plus
#### 官网
https://xiongxyang.gitee.io/home/
#### 新项目小说精品屋-微服务版
基于小说精品屋-plus构建的Spring Cloud 微服务小说门户平台
@ -15,13 +19,9 @@ Gitee仓库地址 https://gitee.com/novel_dev_team/novel-cloud
[点击前往](http://47.106.243.172:8888/)
#### 前言
小说精品屋-plus致力于打造一个完整的商用小说门户平台使用前建议先阅读此文档
#### 项目介绍
小说精品屋-plus是在[小说精品屋](https://github.com/201206030/fiction_house)的基础上去除了漫画和弹幕模块专注于小说是一个多端PC、移动)阅读、功能完善的小说原创/爬虫网站项目既包含了作家专区供原创作者上传小说又提供了爬虫工具通过规则多线程全自动采集任意小说网站数据已兼容99%的小说网站),新书自动入库,老书自动更新
小说精品屋-plus是在[小说精品屋](https://github.com/201206030/fiction_house)的基础上去除了漫画和弹幕模块专注于小说是一个多端PC、WAP)阅读、功能完善的原创文学CMS系统由前台门户系统、作家后台管理系统、平台后台管理系统、爬虫管理系统等多个子系统构成支持会员充值、订阅模式、新闻发布和实时统计报表等功能
小说精品屋-plus重新进行了数据库设计代码重构和功能增强提升了程序整体的可读性和性能增加了很多商用特性主要升级如下
@ -29,6 +29,7 @@ Gitee仓库地址 https://gitee.com/novel_dev_team/novel-cloud
- [x] 服务端代码重构MyBatis3升级为MyBatis3DynamicSql
- [x] 移动站与PC站站点分离浏览器自动识别跳转
- [x] PC站UI更新
- [x] 支持前端模版自定义内置多套模版
- [x] 新闻模块
- [x] 排行榜
- [x] 小说评论模块
@ -44,9 +45,10 @@ Gitee仓库地址 https://gitee.com/novel_dev_team/novel-cloud
```
novel-plus -- 父工程
novel-common -- 通用模块
novel-front -- 前台门户系统
novel-crawl -- 爬虫管理系统
novel-admin -- 后台管理系统
novel-front -- 前台门户&作家后台管理子系统可拆分
novel-crawl -- 爬虫管理系统
novel-admin -- 平台后台管理系统
templates -- 前端模版
```
#### 技术选型
@ -78,9 +80,10 @@ novel-plus -- 父工程
#### 接口文档
[点击查看接口文档示例](./doc/api.md)
[点击查看接口文档示例](doc/api/api.md)
#### PC站截图
#### 橙色主题模版截图
##### PC站截图
1. 首页
@ -134,7 +137,7 @@ novel-plus -- 父工程
![img](https://oscimg.oschina.net/oscnet/up-f849960f4c1303fea77d26e64fc505a7180.png)
#### 手机站截图
##### 手机站截图
1. 首页
@ -152,13 +155,13 @@ novel-plus -- 父工程
<img src="https://s3.ax1x.com/2020/12/04/Dbsew4.jpg" alt="QQ图片20191018161901" style="zoom:33%;" />
#### 爬虫管理系统截图
##### 爬虫管理系统截图
![img](https://s1.ax1x.com/2020/11/03/BsOgbD.png)
![img](https://s1.ax1x.com/2020/11/03/BsOHr8.png)
#### 后台管理系统截图
##### 后台管理系统截图
![img](https://oscimg.oschina.net/oscnet/up-0552343538674a22a64819834100558f39b.png)
@ -168,6 +171,30 @@ novel-plus -- 父工程
![img](https://oscimg.oschina.net/oscnet/up-faf5dda7320674c29a1772bc0c81d74762e.png)
#### 深色主题模版截图
##### PC站截图
1. 首页
![index](https://static.oschina.net/uploads/img/202006/24151811_wIus.png)
##### 手机站截图
1. 首页
![index](https://static.oschina.net/uploads/img/202006/24151812_OOob.jpg)
4. 小说详情页
![微信图片_20190904181558](https://static.oschina.net/uploads/img/202006/24151812_ZosF.png)
5. 目录页
![QQ图片20191018161901](https://static.oschina.net/uploads/img/202006/24151812_Krva.png)
5. 小说阅读页
![QQ图片20191018161901](https://static.oschina.net/uploads/img/202006/24151813_fDgT.png)
#### 安装步骤
##### 数据库安装
@ -175,19 +202,21 @@ novel-plus -- 父工程
1. 安装MySQL软件
2. 修改MySQL`max_allowed_packet `配置建议100M
3. 新建数据库设置编码为utf8mb4
4. 执行sql/novel_plus.sql脚本文件
4. 执行doc/sql/novel_plus.sql脚本文件
##### 爬虫管理系统安装
1. 修改novel-common模块下application-dev.yml文件中的数据库配置
1. 修改novel-common模块下application-common-dev.yml配置文件中的数据库配置
2. 修改novel-crawl模块下application.yml文件中的管理员账号密码
3. 启动程序打开浏览器默认8081端口访问
4. 选择已有或新增爬虫源支持自定义爬虫规则点击`开启`按钮开始爬取小说数据
##### 前台小说门户安装
##### 前台小说门户安装jar包形式部署时需要复制templates文件夹到jar文件的相同目录下
1. 修改novel-common模块下application-dev.yml文件中的数据库配置
2. 启动程序打开浏览器默认8080端口访问
1. 修改novel-common模块下application-common-dev.yml配置文件中的数据库配置
2. 修改novel-front模块下application.yml配置文件中的模版名为你需要使用的模版名templates文件夹下的模版文件夹名内置orange和dark两套模版
![mini-code](https://s3.ax1x.com/2020/12/26/r4uGM6.png)
3. 启动程序打开浏览器默认8080端口访问
**喜欢此项目的可以给我的GitHub和Gitee加个Star支持一下 **
@ -207,9 +236,9 @@ docker安装教程[点击前往](https://my.oschina.net/java2nb/blog/4271989)
#### QQ交流群
![mini-code](https://s1.ax1x.com/2020/10/31/BUQVeI.png)
[点击前往官网查看](https://xiongxyang.gitee.io/home/service.htm)
#### 微信公众号发布最新更新资讯
#### 微信公众号发布最新更新资讯最新前端模版最新爬虫规则技术文档等
![mini-code](https://s3.ax1x.com/2020/12/03/DoImOx.png)

View File

@ -491,13 +491,6 @@ CREATE TABLE `sys_dept` (
-- ----------------------------
-- Records of sys_dept
-- ----------------------------
INSERT INTO `sys_dept` VALUES ('6', '0', '研发部', '1', '1');
INSERT INTO `sys_dept` VALUES ('7', '6', '研發一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('8', '6', '研发二部', '2', '1');
INSERT INTO `sys_dept` VALUES ('9', '0', '销售部', '2', '1');
INSERT INTO `sys_dept` VALUES ('10', '9', '销售一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('11', '0', '产品部', '3', '1');
INSERT INTO `sys_dept` VALUES ('12', '11', '产品一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('13', '0', '测试部', '5', '1');
INSERT INTO `sys_dept` VALUES ('14', '13', '测试一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('15', '13', '测试二部', '2', '1');
@ -894,52 +887,6 @@ CREATE TABLE `sys_log` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1412 DEFAULT CHARSET=utf8 COMMENT='系统日志';
-- ----------------------------
-- Records of sys_log
-- ----------------------------
INSERT INTO `sys_log` VALUES ('1369', '-1', '获取用户信息为空', '登录', '462', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:09:21');
INSERT INTO `sys_log` VALUES ('1370', '-1', '获取用户信息为空', '登录', '19', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:09:26');
INSERT INTO `sys_log` VALUES ('1371', '1', 'admin', '登录', '98', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:09:33');
INSERT INTO `sys_log` VALUES ('1372', '1', 'admin', '请求访问主页', '372', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:09:33');
INSERT INTO `sys_log` VALUES ('1373', '1', 'admin', '请求访问主页', '28', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:12:41');
INSERT INTO `sys_log` VALUES ('1374', '1', 'admin', '编辑角色', '11', 'com.java2nb.system.controller.RoleController.edit()', null, '127.0.0.1', '2020-05-13 11:18:42');
INSERT INTO `sys_log` VALUES ('1375', '1', 'admin', '添加菜单', '2', 'com.java2nb.system.controller.MenuController.add()', null, '127.0.0.1', '2020-05-13 11:19:55');
INSERT INTO `sys_log` VALUES ('1376', '1', 'admin', '保存菜单', '225', 'com.java2nb.system.controller.MenuController.save()', null, '127.0.0.1', '2020-05-13 11:24:42');
INSERT INTO `sys_log` VALUES ('1377', '1', 'admin', '编辑菜单', '15', 'com.java2nb.system.controller.MenuController.edit()', null, '127.0.0.1', '2020-05-13 11:24:54');
INSERT INTO `sys_log` VALUES ('1378', '1', 'admin', '编辑菜单', '11', 'com.java2nb.system.controller.MenuController.edit()', null, '127.0.0.1', '2020-05-13 11:24:58');
INSERT INTO `sys_log` VALUES ('1379', '1', 'admin', '更新菜单', '241', 'com.java2nb.system.controller.MenuController.update()', null, '127.0.0.1', '2020-05-13 11:25:12');
INSERT INTO `sys_log` VALUES ('1380', '1', 'admin', '编辑菜单', '8', 'com.java2nb.system.controller.MenuController.edit()', null, '127.0.0.1', '2020-05-13 11:25:16');
INSERT INTO `sys_log` VALUES ('1381', '1', 'admin', '更新菜单', '199', 'com.java2nb.system.controller.MenuController.update()', null, '127.0.0.1', '2020-05-13 11:25:26');
INSERT INTO `sys_log` VALUES ('1382', '1', 'admin', '编辑角色', '13', 'com.java2nb.system.controller.RoleController.edit()', null, '127.0.0.1', '2020-05-13 11:26:11');
INSERT INTO `sys_log` VALUES ('1383', '1', 'admin', '更新角色', '931', 'com.java2nb.system.controller.RoleController.update()', null, '127.0.0.1', '2020-05-13 11:26:36');
INSERT INTO `sys_log` VALUES ('1384', '-1', '获取用户信息为空', '登录', '11', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:27:02');
INSERT INTO `sys_log` VALUES ('1385', '1', 'admin', '登录', '19', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:27:08');
INSERT INTO `sys_log` VALUES ('1386', '1', 'admin', '请求访问主页', '27', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:27:08');
INSERT INTO `sys_log` VALUES ('1387', '1', 'admin', '登录', '272', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:27:56');
INSERT INTO `sys_log` VALUES ('1388', '1', 'admin', '请求访问主页', '109', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:27:56');
INSERT INTO `sys_log` VALUES ('1389', '1', 'admin', '编辑角色', '8', 'com.java2nb.system.controller.RoleController.edit()', null, '127.0.0.1', '2020-05-13 11:30:36');
INSERT INTO `sys_log` VALUES ('1390', '1', 'admin', '更新角色', '567', 'com.java2nb.system.controller.RoleController.update()', null, '127.0.0.1', '2020-05-13 11:30:42');
INSERT INTO `sys_log` VALUES ('1391', '-1', '获取用户信息为空', '登录', '246', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:31:38');
INSERT INTO `sys_log` VALUES ('1392', '1', 'admin', '登录', '38', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:31:42');
INSERT INTO `sys_log` VALUES ('1393', '1', 'admin', '请求访问主页', '110', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:31:43');
INSERT INTO `sys_log` VALUES ('1394', '1', 'admin', 'error', null, 'http://127.0.0.1/test/order/list', 'org.springframework.jdbc.BadSqlGrammarException: \r\n### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table \'novel_plus.fb_order\' doesn\'t exist\r\n### The error may exist in file [E:\\baseprojectparent\\novel-plus\\novel-admin\\target\\classes\\mybatis\\test\\OrderMapper.xml]\r\n### The error may involve defaultParameterMap\r\n### The error occurred while setting parameters\r\n### SQL: select `id`,`fb_merchant_code`,`merchant_order_sn`,`order_sn`,`platform_order_no`,`trade_no`,`order_state`,`fn_coupon`,`red_packet`,`total_fee`,`order_price`,`fee`,`body`,`attach`,`store_id`,`cashier_id`,`device_no`,`user_id`,`user_logon_id`,`pay_time`,`pay_channel`,`no_cash_coupon_fee`,`cash_coupon_fee`,`cash_fee`,`sign`,`options`,`create_time`,`push_time`,`push_ip`,`mcht_id`,`sn` from fb_order order by id desc limit ?, ?\r\n### Cause: java.sql.SQLSyntaxErrorException: Table \'novel_plus.fb_order\' doesn\'t exist\n; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: Table \'novel_plus.fb_order\' doesn\'t exist', null, '2020-05-13 11:33:27');
INSERT INTO `sys_log` VALUES ('1395', '1', 'admin', '登录', '276', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:39:20');
INSERT INTO `sys_log` VALUES ('1396', '1', 'admin', '请求访问主页', '95', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:39:20');
INSERT INTO `sys_log` VALUES ('1397', '1', 'admin', '登录', '285', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:47:00');
INSERT INTO `sys_log` VALUES ('1398', '1', 'admin', '请求访问主页', '90', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:47:00');
INSERT INTO `sys_log` VALUES ('1399', '1', 'admin', '登录', '251', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 11:48:28');
INSERT INTO `sys_log` VALUES ('1400', '1', 'admin', '请求访问主页', '95', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 11:48:28');
INSERT INTO `sys_log` VALUES ('1401', '1', 'admin', '登录', '302', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 14:09:33');
INSERT INTO `sys_log` VALUES ('1402', '1', 'admin', '请求访问主页', '88', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 14:09:34');
INSERT INTO `sys_log` VALUES ('1403', '1', 'admin', '请求更改用户密码', '3', 'com.java2nb.system.controller.UserController.resetPwd()', null, '127.0.0.1', '2020-05-13 14:11:49');
INSERT INTO `sys_log` VALUES ('1404', '1', 'admin', 'admin提交更改用户密码', '140', 'com.java2nb.system.controller.UserController.adminResetPwd()', null, '127.0.0.1', '2020-05-13 14:11:50');
INSERT INTO `sys_log` VALUES ('1405', '1', 'admin', '请求更改用户密码', '4', 'com.java2nb.system.controller.UserController.resetPwd()', null, '127.0.0.1', '2020-05-13 14:12:11');
INSERT INTO `sys_log` VALUES ('1406', '1', 'admin', '登录', '275', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 14:14:26');
INSERT INTO `sys_log` VALUES ('1407', '1', 'admin', '请求访问主页', '73', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 14:14:27');
INSERT INTO `sys_log` VALUES ('1408', '1', 'admin', 'error', null, 'http://127.0.0.1/novel/author/update', 'org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object \'authorDO\' on field \'id\': rejected value [1,1]; codes [typeMismatch.authorDO.id,typeMismatch.id,typeMismatch.java.lang.Long,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [authorDO.id,id]; arguments []; default message [id]]; default message [Failed to convert property value of type \'java.lang.String\' to required type \'java.lang.Long\' for property \'id\'; nested exception is java.lang.NumberFormatException: For input string: \"1,1\"]', null, '2020-05-13 14:14:38');
INSERT INTO `sys_log` VALUES ('1409', '1', 'admin', 'error', null, 'http://127.0.0.1/novel/author/update', 'org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object \'authorDO\' on field \'id\': rejected value [1,1]; codes [typeMismatch.authorDO.id,typeMismatch.id,typeMismatch.java.lang.Long,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [authorDO.id,id]; arguments []; default message [id]]; default message [Failed to convert property value of type \'java.lang.String\' to required type \'java.lang.Long\' for property \'id\'; nested exception is java.lang.NumberFormatException: For input string: \"1,1\"]', null, '2020-05-13 14:14:47');
INSERT INTO `sys_log` VALUES ('1410', '1', 'admin', '登录', '261', 'com.java2nb.system.controller.LoginController.ajaxLogin()', null, '127.0.0.1', '2020-05-13 14:18:07');
INSERT INTO `sys_log` VALUES ('1411', '1', 'admin', '请求访问主页', '83', 'com.java2nb.system.controller.LoginController.index()', null, '127.0.0.1', '2020-05-13 14:18:07');
-- ----------------------------
-- Table structure for sys_menu
@ -1047,9 +994,6 @@ CREATE TABLE `sys_role` (
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '超级用户角色', 'admin', '拥有最高权限', '2', '2017-08-12 00:43:52', '2017-08-12 19:14:59');
INSERT INTO `sys_role` VALUES ('59', '普通用户', null, '基本用户权限', null, null, null);
INSERT INTO `sys_role` VALUES ('60', '测试', null, '&lt;div&gt;', null, null, null);
INSERT INTO `sys_role` VALUES ('61', 'test', null, '测试', null, null, null);
-- ----------------------------
-- Table structure for sys_role_data_perm
@ -1497,19 +1441,7 @@ CREATE TABLE `sys_user` (
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '超级管理员', 'd633268afedf209e1e4ea0f5f43228a8', '6', 'admin@example.com', '17699999999', '1', '1', '2017-08-15 21:40:39', '2017-08-15 21:41:00', '96', '2017-12-14 00:00:00', '148', 'ccc', '122;121;', '北京市', '北京市市辖区', '东城区');
INSERT INTO `sys_user` VALUES ('2', 'test', '临时用户', 'd0af8fa1272ef5a152d9e27763eea293', '6', 'test@bootdo.com', null, '1', '1', '2017-08-14 13:43:05', '2017-08-14 21:15:36', null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('36', 'ldh', '刘德华', 'bfd9394475754fbe45866eba97738c36', '7', 'ldh@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('123', 'zxy', '张学友', '35174ba93f5fe7267f1fb3c1bf903781', '6', 'zxy@bootdo', null, '0', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('124', 'wyf', '吴亦凡', 'e179e6f687bbd57b9d7efc4746c8090a', '6', 'wyf@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('130', 'lh', '鹿晗', '7924710cd673f68967cde70e188bb097', '9', 'lh@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('131', 'lhc', '令狐冲', 'd515538e17ecb570ba40344b5618f5d4', '6', 'lhc@bootdo.com', null, '0', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('132', 'lyf', '刘亦菲', '7fdb1d9008f45950c1620ba0864e5fbd', '13', 'lyf@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('134', 'lyh', '李彦宏', 'dc26092b3244d9d432863f2738180e19', '8', 'lyh@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('135', 'wjl', '王健林', '3967697dfced162cf6a34080259b83aa', '6', 'wjl@bootod.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('136', 'gdg', '郭德纲', '3bb1bda86bc02bf6478cd91e42135d2f', '9', 'gdg@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('137', 'test2', 'test2', '649169898e69272c0e5bc899baf1e904', null, '1179705413@qq.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('138', 'test3', 'test3', '79ba2d0b58d8a2e94f6b18744c8cd280', '16', '1179705413@qq.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('1', 'admin', '超级管理员', 'd633268afedf209e1e4ea0f5f43228a8', '14', 'admin@example.com', '17699999999', '1', '1', '2017-08-15 21:40:39', '2017-08-15 21:41:00', '96', '2017-12-14 00:00:00', '148', 'ccc', '122;121;', '北京市', '北京市市辖区', '东城区');
-- ----------------------------
-- Table structure for sys_user_role

View File

@ -5,7 +5,7 @@
<groupId>com.java2nb</groupId>
<artifactId>novel-admin</artifactId>
<version>3.1.0</version>
<version>3.3.0</version>
<packaging>jar</packaging>
<name>novel-admin</name>

View File

@ -1,5 +1,5 @@
java2nb:
uploadPath: c:/var/java2nb/uploaded_files/
uploadPath: /var/pic/
username: admin
password: 111111
logging:
@ -10,7 +10,7 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/novel_plus?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: test123456
#password:

View File

@ -147,7 +147,7 @@
<tr>
<td>下载地址</td>
<td>
<a href="https://gitee.com/xiongxyang/fiction_house" target="_blank">Gitee</a> /
<a href="https://gitee.com/novel_dev_team/fiction_house" target="_blank">Gitee</a> /
<a href="https://github.com/201206030/fiction_house" target="_blank">Github</a>
</td>
</tr>
@ -155,8 +155,8 @@
<td>Gitee</td>
<td style="padding-bottom: 0;">
<div class="layui-btn-container">
<a href='https://gitee.com/xiongxyang/fiction_house/stargazers'><img src='https://gitee.com/xiongxyang/fiction_house/badge/star.svg?theme=dark' alt='star'></img></a>
<a href='https://gitee.com/xiongxyang/fiction_house/members'><img src='https://gitee.com/xiongxyang/fiction_house/badge/fork.svg?theme=dark' alt='fork'></img></a>
<a href='https://gitee.com/novel_dev_team/fiction_house/stargazers'><img src='https://gitee.com/novel_dev_team/fiction_house/badge/star.svg?theme=dark' alt='star'></img></a>
<a href='https://gitee.com/novel_dev_team/fiction_house/members'><img src='https://gitee.com/novel_dev_team/fiction_house/badge/fork.svg?theme=dark' alt='fork'></img></a>
</div>
</td>
</tr>
@ -200,7 +200,7 @@
<tr>
<td>下载地址</td>
<td>
<a href="https://gitee.com/xiongxyang/novel-plus" target="_blank">Gitee</a> /
<a href="https://gitee.com/novel_dev_team/novel-plus" target="_blank">Gitee</a> /
<a href="https://github.com/201206030/novel-plus" target="_blank">Github</a>
</td>
</tr>
@ -208,8 +208,8 @@
<td>Gitee</td>
<td style="padding-bottom: 0;">
<div class="layui-btn-container">
<a href='https://gitee.com/xiongxyang/novel-plus/stargazers'><img src='https://gitee.com/xiongxyang/novel-plus/badge/star.svg?theme=dark' alt='star'></img></a>
<a href='https://gitee.com/xiongxyang/novel-plus/members'><img src='https://gitee.com/xiongxyang/novel-plus/badge/fork.svg?theme=dark' alt='fork'></img></a>
<a href='https://gitee.com/novel_dev_team/novel-plus/stargazers'><img src='https://gitee.com/novel_dev_team/novel-plus/badge/star.svg?theme=dark' alt='star'></img></a>
<a href='https://gitee.com/novel_dev_team/novel-plus/members'><img src='https://gitee.com/novel_dev_team/novel-plus/badge/fork.svg?theme=dark' alt='fork'></img></a>
</div>
</td>
</tr>
@ -253,7 +253,7 @@
<tr>
<td>下载地址</td>
<td>
<a href="https://gitee.com/xiongxyang/novel-cloud" target="_blank">Gitee</a> /
<a href="https://gitee.com/novel_dev_team/novel-cloud" target="_blank">Gitee</a> /
<a href="https://github.com/201206030/novel-cloud" target="_blank">Github</a>
</td>
</tr>
@ -261,8 +261,8 @@
<td>Gitee</td>
<td style="padding-bottom: 0;">
<div class="layui-btn-container">
<a href='https://gitee.com/xiongxyang/novel-cloud/stargazers'><img src='https://gitee.com/xiongxyang/novel-cloud/badge/star.svg?theme=dark' alt='star'></img></a>
<a href='https://gitee.com/xiongxyang/novel-cloud/members'><img src='https://gitee.com/xiongxyang/novel-cloud/badge/fork.svg?theme=dark' alt='fork'></img></a>
<a href='https://gitee.com/novel_dev_team/novel-cloud/stargazers'><img src='https://gitee.com/novel_dev_team/novel-cloud/badge/star.svg?theme=dark' alt='star'></img></a>
<a href='https://gitee.com/novel_dev_team/novel-cloud/members'><img src='https://gitee.com/novel_dev_team/novel-cloud/badge/fork.svg?theme=dark' alt='fork'></img></a>
</div>
</td>
</tr>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>novel</artifactId>
<groupId>com.java2nb</groupId>
<version>3.1.0</version>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,21 +1,30 @@
package com.java2nb.novel.core.advice;
import com.java2nb.novel.core.bean.ResultBean;
import com.java2nb.novel.core.enums.ResponseStatus;
import com.java2nb.novel.core.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 通用的异常处理器
*
* @author 11797*/
@Slf4j
@ControllerAdvice
@ResponseBody
@RestControllerAdvice(basePackages = "com.java2nb.novel.controller")
public class CommonExceptionHandler {
/**
* 处理后台数据校验异常
* */
@ExceptionHandler(BindException.class)
public ResultBean handlerBindException(BindException e){
log.error(e.getMessage(),e);
return ResultBean.fail(ResponseStatus.PARAM_ERROR);
}
/**
* 处理业务异常
* */

View File

@ -0,0 +1,26 @@
package com.java2nb.novel.core.advice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* 页面异常处理器
*
* @author 11797
*/
@Slf4j
@ControllerAdvice(basePackages = "com.java2nb.novel.page")
public class PageExceptionHandler {
/**
* 处理所有异常
*/
@ExceptionHandler(Exception.class)
public String handlerException(Exception e) {
log.error(e.getMessage(), e);
//跳转页面过程中出现异常时统一跳转到404页面
return "404";
}
}

View File

@ -0,0 +1,11 @@
package com.java2nb.novel.core.valid;
/**
* 新增数据的校验分组
* @author xiongxiaoyang
*/
public interface AddGroup {
}

View File

@ -0,0 +1,11 @@
package com.java2nb.novel.core.valid;
/**
* 更新数据的校验分组
* @author xiongxiaoyang
*/
public interface UpdateGroup {
}

View File

@ -1,36 +1,56 @@
package com.java2nb.novel.entity;
import com.java2nb.novel.core.valid.AddGroup;
import com.java2nb.novel.core.valid.UpdateGroup;
import java.util.Date;
import javax.annotation.Generated;
import javax.validation.constraints.*;
public class User {
@Null(groups = {AddGroup.class, UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private Long id;
@NotBlank(groups = {AddGroup.class},message="手机号不能为空!")
@Pattern(groups = {AddGroup.class},regexp="^1[3|4|5|6|7|8|9][0-9]{9}$",message="手机号格式不正确!")
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private String username;
@NotBlank(groups = {AddGroup.class},message="密码不能为空!")
@Null(groups = {UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private String password;
@Null(groups = {AddGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private String nickName;
@Null(groups = {AddGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private String userPhoto;
@Null(groups = {AddGroup.class})
@Min(value = 0,groups = {UpdateGroup.class})
@Max(value = 1,groups = {UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private Byte userSex;
@Null(groups = {AddGroup.class,UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private Long accountBalance;
@Null(groups = {AddGroup.class,UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private Byte status;
@Null(groups = {AddGroup.class,UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private Date createTime;
@Null(groups = {AddGroup.class,UpdateGroup.class})
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private Date updateTime;

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>novel</artifactId>
<groupId>com.java2nb</groupId>
<version>3.1.0</version>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,9 +1,6 @@
package com.java2nb.novel.core.crawl;
import com.java2nb.novel.core.utils.HttpUtil;
import com.java2nb.novel.core.utils.IdWorker;
import com.java2nb.novel.core.utils.RandomBookInfoUtil;
import com.java2nb.novel.core.utils.RestTemplateUtil;
import com.java2nb.novel.core.utils.*;
import com.java2nb.novel.entity.Book;
import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.entity.BookIndex;
@ -37,7 +34,7 @@ public class CrawlParser {
private static RestTemplate restTemplate = RestTemplateUtil.getInstance("utf-8");
private static ThreadLocal <Integer> retryCount = new ThreadLocal<>();
private static ThreadLocal<Integer> retryCount = new ThreadLocal<>();
@SneakyThrows
public static Book parseBook(RuleBean ruleBean, String bookId) {
@ -65,7 +62,7 @@ public class CrawlParser {
boolean isFindPicUrl = picUrlMatch.find();
if (isFindPicUrl) {
String picUrl = picUrlMatch.group(1);
if(StringUtils.isNotBlank(picUrl) && StringUtils.isNotBlank(ruleBean.getPicUrlPrefix())) {
if (StringUtils.isNotBlank(picUrl) && StringUtils.isNotBlank(ruleBean.getPicUrlPrefix())) {
picUrl = ruleBean.getPicUrlPrefix() + picUrl;
}
//设置封面图片路径
@ -96,11 +93,11 @@ public class CrawlParser {
String desc = bookDetailHtml.substring(bookDetailHtml.indexOf(ruleBean.getDescStart()) + ruleBean.getDescStart().length());
desc = desc.substring(0, desc.indexOf(ruleBean.getDescEnd()));
//过滤掉简介中的特殊标签
desc = desc.replaceAll("<a[^<]+</a>","")
.replaceAll("<font[^<]+</font>","")
.replaceAll("<p>\\s*</p>","")
.replaceAll("<p>","")
.replaceAll("</p>","<br/>");
desc = desc.replaceAll("<a[^<]+</a>", "")
.replaceAll("<font[^<]+</font>", "")
.replaceAll("<p>\\s*</p>", "")
.replaceAll("<p>", "")
.replaceAll("</p>", "<br/>");
//设置书籍简介
book.setBookDesc(desc);
if (StringUtils.isNotBlank(ruleBean.getStatusPatten())) {
@ -146,9 +143,9 @@ public class CrawlParser {
}
public static Map<Integer, List> parseBookIndexAndContent(String sourceBookId, Book book, RuleBean ruleBean, Map<Integer, BookIndex> hasIndexs) {
Map<Integer,List> result = new HashMap<>(2);
result.put(BOOK_INDEX_LIST_KEY,new ArrayList(0));
result.put(BOOK_CONTENT_LIST_KEY,new ArrayList(0));
Map<Integer, List> result = new HashMap<>(2);
result.put(BOOK_INDEX_LIST_KEY, new ArrayList(0));
result.put(BOOK_CONTENT_LIST_KEY, new ArrayList(0));
Date currentDate = new Date();
@ -159,7 +156,7 @@ public class CrawlParser {
String indexListHtml = getByHttpClientWithChrome(indexListUrl);
if (indexListHtml != null) {
if(StringUtils.isNotBlank(ruleBean.getBookIndexStart())){
if (StringUtils.isNotBlank(ruleBean.getBookIndexStart())) {
indexListHtml = indexListHtml.substring(indexListHtml.indexOf(ruleBean.getBookIndexStart()) + ruleBean.getBookIndexStart().length());
}
@ -174,10 +171,7 @@ public class CrawlParser {
int indexNum = 0;
//总字数
Integer totalWordCount = 0;
//最新目录
Long lastIndexId = null;
String lastIndexName = null;
Integer totalWordCount = book.getWordCount() == null ? 0 : book.getWordCount();
while (isFindIndex) {
@ -189,12 +183,12 @@ public class CrawlParser {
String sourceIndexId = indexIdMatch.group(1);
String bookContentUrl = ruleBean.getBookContentUrl();
int calStart = bookContentUrl.indexOf("{cal_");
if(calStart != -1){
if (calStart != -1) {
//内容页URL需要进行计算才能得到
String calStr = bookContentUrl.substring(calStart,calStart+bookContentUrl.substring(calStart).indexOf("}"));
String calStr = bookContentUrl.substring(calStart, calStart + bookContentUrl.substring(calStart).indexOf("}"));
String[] calArr = calStr.split("_");
int calType = Integer.parseInt(calArr[1]);
if(calType == 1) {
if (calType == 1) {
///{cal_1_1_3}_{bookId}/{indexId}.html
//第一种计算规则去除第x个参数的最后y个字母
int x = Integer.parseInt(calArr[2]);
@ -206,12 +200,12 @@ public class CrawlParser {
calResult = sourceIndexId.substring(0, sourceBookId.length() - y);
}
if(calResult.length() == 0){
if (calResult.length() == 0) {
calResult = "0";
}
bookContentUrl = bookContentUrl.replace(calStr+"}", calResult);
bookContentUrl = bookContentUrl.replace(calStr + "}", calResult);
}
}
@ -223,54 +217,43 @@ public class CrawlParser {
if (contentHtml != null && !contentHtml.contains("正在手打中")) {
String content = contentHtml.substring(contentHtml.indexOf(ruleBean.getContentStart()) + ruleBean.getContentStart().length());
content = content.substring(0, content.indexOf(ruleBean.getContentEnd()));
//TODO插入章节目录和章节内容
//插入章节目录和章节内容
BookIndex bookIndex = new BookIndex();
bookIndex.setIndexName(indexName);
bookIndex.setIndexNum(indexNum);
Integer wordCount = StringUtil.getStrValidWordCount(content);
bookIndex.setWordCount(wordCount);
indexList.add(bookIndex);
BookContent bookContent = new BookContent();
BookContent bookContent = new BookContent();
bookContent.setContent(content);
contentList.add(bookContent);
//判断是新增还是更新
if(hasIndexs.size() == 0){
//新书入库
if (hasIndex != null) {
//章节更新
bookIndex.setId(hasIndex.getId());
bookContent.setIndexId(hasIndex.getId());
//计算总字数
totalWordCount = (totalWordCount+wordCount-hasIndex.getWordCount());
} else {
//章节插入
//设置目录和章节内容
Long indexId = idWorker.nextId();
lastIndexId = indexId;
lastIndexName = indexName;
bookIndex.setId(indexId);
bookIndex.setBookId(book.getId());
Integer wordCount = bookContent.getContent().length();
totalWordCount += wordCount;
bookIndex.setWordCount(wordCount);
bookIndex.setCreateTime(currentDate);
bookIndex.setUpdateTime(currentDate);
bookContent.setIndexId(indexId);
//设置小说基础信息
book.setWordCount(totalWordCount);
book.setLastIndexId(lastIndexId);
book.setLastIndexName(lastIndexName);
book.setLastIndexUpdateTime(currentDate);
book.setCreateTime(currentDate);
book.setUpdateTime(currentDate);
}else{
//老书更新
//计算总字数
totalWordCount += wordCount;
}
bookIndex.setUpdateTime(currentDate);
if(hasIndex != null){
bookIndex.setId(hasIndex.getId());
bookContent.setIndexId(hasIndex.getId());
}
}
@ -279,15 +262,29 @@ public class CrawlParser {
isFindIndex = indexIdMatch.find() & indexNameMatch.find();
}
if (indexList.size() > 0) {
//如果有爬到最新章节,则设置小说主表的最新章节信息
//获取爬取到的最新章节
BookIndex lastIndex = indexList.get(indexList.size()-1);
book.setLastIndexId(lastIndex.getId());
book.setLastIndexName(lastIndex.getIndexName());
book.setLastIndexUpdateTime(currentDate);
}
book.setWordCount(totalWordCount);
book.setUpdateTime(currentDate);
if (indexList.size() == contentList.size() && indexList.size() > 0) {
result.put(BOOK_INDEX_LIST_KEY,indexList);
result.put(BOOK_CONTENT_LIST_KEY,contentList);
result.put(BOOK_INDEX_LIST_KEY, indexList);
result.put(BOOK_CONTENT_LIST_KEY, contentList);
}
}
return result;
}
@ -297,7 +294,7 @@ public class CrawlParser {
ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
if (forEntity.getStatusCode() == HttpStatus.OK) {
String body = forEntity.getBody();
if(body.length() < Constants.INVALID_HTML_LENGTH){
if (body.length() < Constants.INVALID_HTML_LENGTH) {
return processErrorHttpResult(url);
}
//成功获得html内容
@ -314,11 +311,11 @@ public class CrawlParser {
try {
String body = HttpUtil.getByHttpClientWithChrome(url);
if(body != null && body.length() < Constants.INVALID_HTML_LENGTH){
return processErrorHttpResult(url);
}
//成功获得html内容
return body;
if (body != null && body.length() < Constants.INVALID_HTML_LENGTH) {
return processErrorHttpResult(url);
}
//成功获得html内容
return body;
} catch (Exception e) {
e.printStackTrace();
}
@ -327,13 +324,13 @@ public class CrawlParser {
}
@SneakyThrows
private static String processErrorHttpResult(String url){
private static String processErrorHttpResult(String url) {
Integer count = retryCount.get();
if(count == null){
if (count == null) {
count = 0;
}
if(count < Constants.HTTP_FAIL_RETRY_COUNT){
Thread.sleep( new Random().nextInt(10*1000));
if (count < Constants.HTTP_FAIL_RETRY_COUNT) {
Thread.sleep(new Random().nextInt(10 * 1000));
retryCount.set(++count);
return getByHttpClient(url);
}

View File

@ -58,6 +58,7 @@ public class StarterListener implements ServletContextListener {
Book book = CrawlParser.parseBook(ruleBean, needUpdateBook.getCrawlBookId());
//这里只做老书更新
book.setId(needUpdateBook.getId());
book.setWordCount(needUpdateBook.getWordCount());
if (needUpdateBook.getPicUrl() != null && needUpdateBook.getPicUrl().contains(Constants.LOCAL_PIC_PREFIX)) {
//本地图片则不更新
book.setPicUrl(null);

View File

@ -65,9 +65,8 @@ public interface BookService {
* @param book 小说数据
* @param bookIndexList 目录集合
* @param bookContentList 内容集合
* @param existBookIndexMap 已存在的章节Map
* */
void updateBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList, Map<Integer, BookIndex> existBookIndexMap);
* @param existBookIndexMap 已存在的章节Map */
void updateBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList, Map<Integer, BookIndex> existBookIndexMap);
/**
* 更新一下最后一次的抓取时间

View File

@ -1,6 +1,5 @@
package com.java2nb.novel.service.impl;
import com.java2nb.novel.core.utils.IdWorker;
import com.java2nb.novel.entity.Book;
import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.entity.BookIndex;
@ -79,12 +78,9 @@ public class BookServiceImpl implements BookService {
if(bookIndexList.size()>0) {
if (book.getId() == null) {
book.setId(new IdWorker().nextId());
}
//保存小说主表
book.setCreateTime(new Date());
bookMapper.insertSelective(book);
//批量保存目录和内容
@ -109,7 +105,7 @@ public class BookServiceImpl implements BookService {
@Override
public Map<Integer, BookIndex> queryExistBookIndexMap(Long bookId) {
List<BookIndex> bookIndexs = bookIndexMapper.selectMany(select(BookIndexDynamicSqlSupport.id,BookIndexDynamicSqlSupport.indexNum,BookIndexDynamicSqlSupport.indexName)
List<BookIndex> bookIndexs = bookIndexMapper.selectMany(select(BookIndexDynamicSqlSupport.id,BookIndexDynamicSqlSupport.indexNum,BookIndexDynamicSqlSupport.indexName,BookIndexDynamicSqlSupport.wordCount)
.from(BookIndexDynamicSqlSupport.bookIndex)
.where(BookIndexDynamicSqlSupport.bookId,isEqualTo(bookId))
.build()
@ -122,36 +118,19 @@ public class BookServiceImpl implements BookService {
@Transactional(rollbackFor = Exception.class)
@Override
public void updateBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList, Map<Integer, BookIndex> existBookIndexMap) {
Date currentDate = new Date();
public void updateBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList, Map<Integer, BookIndex> existBookIndexMap) {
for (int i = 0; i < bookIndexList.size(); i++) {
BookIndex bookIndex = bookIndexList.get(i);
BookContent bookContent = bookContentList.get(i);
//插入或更新目录
Integer wordCount = bookContent.getContent().length();
bookIndex.setWordCount(wordCount);
bookIndex.setUpdateTime(currentDate);
if(bookIndex.getId() == null) {
if(!existBookIndexMap.containsKey(bookIndex.getIndexNum())) {
//插入
bookIndex.setBookId(book.getId());
Long indexId = new IdWorker().nextId();
bookIndex.setId(indexId);
bookIndex.setCreateTime(currentDate);
bookIndexMapper.insertSelective(bookIndex);
}else{
//更新
bookIndexMapper.updateByPrimaryKeySelective(bookIndex);
}
if(bookContent.getIndexId() == null) {
//插入
bookContent.setIndexId(bookIndex.getId());
bookContentMapper.insertSelective(bookContent);
}else{
//更新
bookIndexMapper.updateByPrimaryKeySelective(bookIndex);
bookContentMapper.update(update(BookContentDynamicSqlSupport.bookContent)
.set(BookContentDynamicSqlSupport.content)
.equalTo(bookContent.getContent())
@ -160,21 +139,10 @@ public class BookServiceImpl implements BookService {
.render(RenderingStrategies.MYBATIS3));
}
}
//更新小说主表
if(bookIndexList.size()>0) {
//有更新章节,才需要更新以下字段
book.setWordCount(queryTotalWordCount(book.getId()));
BookIndex lastIndex = bookIndexList.get(bookIndexList.size()-1);
if(!existBookIndexMap.containsKey(lastIndex.getIndexNum())) {
//如果最新章节不在已存在章节中,那么更新小说表最新章节信息
book.setLastIndexId(lastIndex.getId());
book.setLastIndexName(lastIndex.getIndexName());
book.setLastIndexUpdateTime(currentDate);
}
}
book.setUpdateTime(currentDate);
book.setBookName(null);
book.setAuthorName(null);
if(Constants.VISIT_COUNT_DEFAULT.equals(book.getVisitCount())) {

View File

@ -5,7 +5,7 @@
<select id="queryNeedUpdateBook" resultType="com.java2nb.novel.entity.Book">
select id,crawl_source_id,crawl_book_id,crawl_last_time,pic_url
select id,crawl_source_id,crawl_book_id,crawl_last_time,pic_url,word_count
from book where last_index_update_time > #{startDate} and crawl_source_id is not null
order by crawl_last_time
limit ${limit}
@ -15,8 +15,7 @@
<select id="queryTotalWordCount" parameterType="long" resultType="int">
select sum(t2.word_count) from book t1 inner join book_index t2
on t1.id = t2.book_id and t1.id = #{bookId}
select sum(word_count) from book_index where book_id = #{bookId}
</select>
<update id="updateCrawlLastTime">

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>novel</artifactId>
<groupId>com.java2nb</groupId>
<version>3.1.0</version>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,15 +6,16 @@ import com.java2nb.novel.core.bean.UserDetails;
import com.java2nb.novel.core.cache.CacheService;
import com.java2nb.novel.core.enums.ResponseStatus;
import com.java2nb.novel.core.utils.RandomValidateCodeUtil;
import com.java2nb.novel.core.valid.AddGroup;
import com.java2nb.novel.core.valid.UpdateGroup;
import com.java2nb.novel.entity.User;
import com.java2nb.novel.entity.UserBuyRecord;
import com.java2nb.novel.form.UserForm;
import com.java2nb.novel.service.BookService;
import com.java2nb.novel.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
@ -42,12 +43,7 @@ public class UserController extends BaseController {
* 登陆
*/
@PostMapping("login")
public ResultBean login(@Valid UserForm user, BindingResult result) {
//判断参数是否合法
if (result.hasErrors()) {
log.info(result.getAllErrors().toString());
return ResultBean.fail(ResponseStatus.PARAM_ERROR);
}
public ResultBean login(User user) {
//登陆
UserDetails userDetails = userService.login(user);
@ -64,13 +60,8 @@ public class UserController extends BaseController {
* 注册
*/
@PostMapping("register")
public ResultBean register(@Valid UserForm user, @RequestParam(value = "velCode", defaultValue = "") String velCode, BindingResult result) {
public ResultBean register(@Validated({AddGroup.class}) User user, @RequestParam(value = "velCode", defaultValue = "") String velCode) {
//判断参数是否合法
if (result.hasErrors()) {
log.info(result.getAllErrors().toString());
return ResultBean.fail(ResponseStatus.PARAM_ERROR);
}
//判断验证码是否正确
if (!velCode.equals(cacheService.get(RandomValidateCodeUtil.RANDOM_CODE_KEY))) {
@ -225,7 +216,7 @@ public class UserController extends BaseController {
* 更新个人信息
* */
@PostMapping("updateUserInfo")
public ResultBean updateUserInfo(User user,HttpServletRequest request) {
public ResultBean updateUserInfo(@Validated({UpdateGroup.class}) User user, HttpServletRequest request) {
UserDetails userDetails = getUserDetails(request);
if (userDetails == null) {
return ResultBean.fail(ResponseStatus.NO_LOGIN);

View File

@ -0,0 +1,25 @@
package com.java2nb.novel.core.config;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
/**
* 错误页面配置
* @author xiongxiaoyang
*/
@Configuration
public class ErrorPageConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
/*1.错误类型为404默认显示404.html网页*/
ErrorPage e404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
/**
TODO 2.错误类型为500表示服务器响应错误默认显示/500.html网页
*/
registry.addErrorPages(e404);
}
}

View File

@ -86,7 +86,11 @@ public class JwtTokenUtil {
*/
private boolean isTokenExpired(String token) {
Date expiredDate = getExpiredDateFromToken(token);
return expiredDate.before(new Date());
if(expiredDate == null){
return true;
}else {
return expiredDate.before(new Date());
}
}
/**
@ -94,7 +98,7 @@ public class JwtTokenUtil {
*/
private Date getExpiredDateFromToken(String token) {
Claims claims = getClaimsFromToken(token);
return claims.getExpiration();
return claims != null ? claims.getExpiration() : null;
}
/**

View File

@ -1,20 +0,0 @@
package com.java2nb.novel.form;
import lombok.Data;
import javax.annotation.Generated;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@Data
public class UserForm {
@NotBlank(message="手机号不能为空!")
@Pattern(regexp="^1[3|4|5|6|7|8|9][0-9]{9}$",message="手机号格式不正确!")
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private String username;
@NotBlank(message="密码不能为空!")
@Generated("org.mybatis.generator.api.MyBatisGenerator")
private String password;
}

View File

@ -1,6 +1,6 @@
package com.java2nb.novel.controller;
package com.java2nb.novel.page;
import com.java2nb.novel.core.bean.ResultBean;
import com.java2nb.novel.controller.BaseController;
import com.java2nb.novel.core.bean.UserDetails;
import com.java2nb.novel.core.utils.ThreadLocalUtil;
import com.java2nb.novel.entity.*;
@ -9,16 +9,16 @@ import com.java2nb.novel.service.BookService;
import com.java2nb.novel.service.NewsService;
import com.java2nb.novel.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@ -27,7 +27,7 @@ import java.util.List;
@Slf4j
@RequiredArgsConstructor
@Controller
public class PageController extends BaseController{
public class PageController extends BaseController {
private final BookService bookService;
@ -97,6 +97,7 @@ public class PageController extends BaseController{
/**
* 详情页
* */
@SneakyThrows
@RequestMapping("/book/{bookId}.html")
public String bookDetail(@PathVariable("bookId") Long bookId, Model model) {
Book book = bookService.queryBookDetail(bookId);
@ -112,6 +113,7 @@ public class PageController extends BaseController{
/**
* 目录页
* */
@SneakyThrows
@RequestMapping("/book/indexList-{bookId}.html")
public String indexList(@PathVariable("bookId") Long bookId, Model model) {
Book book = bookService.queryBookDetail(bookId);
@ -125,13 +127,14 @@ public class PageController extends BaseController{
/**
* 内容页
* */
@SneakyThrows
@RequestMapping("/book/{bookId}/{bookIndexId}.html")
public String indexList(@PathVariable("bookId") Long bookId,@PathVariable("bookIndexId") Long bookIndexId, HttpServletRequest request,Model model) {
public String indexList(@PathVariable("bookId") Long bookId,@PathVariable("bookIndexId") Long bookIndexId, HttpServletRequest request, Model model) {
//查询书籍
Book book = bookService.queryBookDetail(bookId);
model.addAttribute("book",book);
//查询目录
BookIndex bookIndex = bookService.queryBookIndex(bookIndexId);
model.addAttribute("book",book);
model.addAttribute("bookIndex",bookIndex);
//查询上一章节目录ID
Long preBookIndexId = bookService.queryPreBookIndexId(bookId,bookIndex.getIndexNum());

View File

@ -3,7 +3,6 @@ package com.java2nb.novel.service;
import com.java2nb.novel.core.bean.UserDetails;
import com.java2nb.novel.entity.UserBuyRecord;
import com.java2nb.novel.form.UserForm;
import com.java2nb.novel.vo.BookReadHistoryVO;
import com.java2nb.novel.vo.BookShelfVO;
import com.java2nb.novel.entity.User;
@ -19,17 +18,17 @@ public interface UserService {
/**
* 用户注册
* @param form 用户注册提交信息类
* @param user 用户注册信息类
* @return jwt载体信息类
* */
UserDetails register(UserForm form);
UserDetails register(User user);
/**
* 用户登陆
* @param form 用户登陆提交信息类
* @param user 用户登陆信息类
* @return jwt载体信息类
* */
UserDetails login(UserForm form);
UserDetails login(User user);
/**
* 查询小说是否已加入书架

View File

@ -5,7 +5,6 @@ import com.java2nb.novel.core.bean.UserDetails;
import com.java2nb.novel.core.utils.BeanUtil;
import com.java2nb.novel.entity.*;
import com.java2nb.novel.entity.User;
import com.java2nb.novel.form.UserForm;
import com.java2nb.novel.service.UserService;
import com.java2nb.novel.core.enums.ResponseStatus;
import com.java2nb.novel.core.exception.BusinessException;
@ -29,7 +28,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import static com.java2nb.novel.mapper.BookDynamicSqlSupport.book;
import static com.java2nb.novel.mapper.BookDynamicSqlSupport.id;
import static com.java2nb.novel.mapper.UserBookshelfDynamicSqlSupport.userBookshelf;
import static com.java2nb.novel.mapper.UserDynamicSqlSupport.*;
@ -59,11 +57,11 @@ public class UserServiceImpl implements UserService {
@Override
public UserDetails register(UserForm form) {
public UserDetails register(User user) {
//查询用户名是否已注册
SelectStatementProvider selectStatement = select(count(id))
.from(user)
.where(username, isEqualTo(form.getUsername()))
.from(UserDynamicSqlSupport.user)
.where(username, isEqualTo(user.getUsername()))
.build()
.render(RenderingStrategies.MYBATIS3);
long count = userMapper.count(selectStatement);
@ -72,7 +70,7 @@ public class UserServiceImpl implements UserService {
throw new BusinessException(ResponseStatus.USERNAME_EXIST);
}
User entity = new User();
BeanUtils.copyProperties(form,entity);
BeanUtils.copyProperties(user,entity);
//数据库生成注册记录
Long id = new IdWorker().nextId();
entity.setId(id);
@ -91,12 +89,12 @@ public class UserServiceImpl implements UserService {
}
@Override
public UserDetails login(UserForm form) {
public UserDetails login(User user) {
//根据用户名密码查询记录
SelectStatementProvider selectStatement = select(id, username,nickName)
.from(user)
.where(username, isEqualTo(form.getUsername()))
.and(password, isEqualTo(MD5Util.MD5Encode(form.getPassword(), Charsets.UTF_8.name())))
.from(UserDynamicSqlSupport.user)
.where(username, isEqualTo(user.getUsername()))
.and(password, isEqualTo(MD5Util.MD5Encode(user.getPassword(), Charsets.UTF_8.name())))
.build()
.render(RenderingStrategies.MYBATIS3);
List<User> users = userMapper.selectMany(selectStatement);
@ -105,10 +103,10 @@ public class UserServiceImpl implements UserService {
}
//生成UserDetail对象并返回
UserDetails userDetails = new UserDetails();
User user = users.get(0);
user = users.get(0);
userDetails.setId(user.getId());
userDetails.setNickName(user.getNickName());
userDetails.setUsername(form.getUsername());
userDetails.setUsername(user.getUsername());
return userDetails;
}
@ -232,12 +230,9 @@ public class UserServiceImpl implements UserService {
@Override
public void updateUserInfo(Long userId, User user) {
User updateUser = new User();
updateUser.setId(userId);
updateUser.setNickName(user.getNickName());
updateUser.setUserSex(user.getUserSex());
updateUser.setUpdateTime(new Date());
userMapper.updateByPrimaryKeySelective(updateUser);
user.setId(userId);
user.setUpdateTime(new Date());
userMapper.updateByPrimaryKeySelective(user);
}

View File

@ -25,6 +25,14 @@ spring:
jest:
uris: http://127.0.0.1:9200
#thymeleaf模版路径配置
thymeleaf:
prefix: file:${user.dir}/templates/${templates.name}/html/
suffix: .html
#静态文件路径配置
resources:
static-locations: file:${user.dir}/templates/${templates.name}/static/
redisson:
singleServerConfig:
address: 127.0.0.1:6379
@ -65,3 +73,13 @@ book:
word-count: 1000
#价值(屋币)
value: 5
#模版配置
templates:
name: orange

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Not Found</title>
<script>
setTimeout(function () {
location.href = '/';
},3000)
</script>
</head>
<body style="background: url(/images/404.jpeg) no-repeat;" >
</body>
</html>

View File

@ -5,7 +5,7 @@
<groupId>com.java2nb</groupId>
<artifactId>novel</artifactId>
<version>3.1.0</version>
<version>3.3.0</version>
<modules>
<module>novel-common</module>
<module>novel-front</module>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Not Found</title>
<script>
setTimeout(function () {
location.href = '/';
},3000)
</script>
</head>
<body style="background: url(/images/404.jpeg) no-repeat;" >
</body>
</html>

View File

@ -0,0 +1,364 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta th:if="${catId == 9}" name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=1">
<meta th:if="${catId != 9}" name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:utext="${book.bookName}+${bookIndex.indexName}"></title>
<meta name="keywords" th:content="${book.bookName}+','+${bookIndex.indexName}">
<meta name="description"
th:content="${book.bookName}+'最新更新章节免费在线阅读TXT下载'">
<div th:include="common/css :: css"></div>
<script type="text/javascript">
function reinitIframe(){
var iframe = document.getElementById("frame_content");
try{
iframe.height =  iframe.contentWindow.document.documentElement.scrollHeight;
}catch (ex){}
}
window.setInterval("reinitIframe()", 200);
</script>
<script th:fragment="js" src="/js/jquery-1.9.1.js"></script>
<script th:fragment="js" src="/layui/layui.all.js"></script>
</div>
<style type="text/css">
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indexP p a {
color: #4c6978;
}
.Readarea {
font-size: 18px;
line-height: 35px;
padding: 10px;
color: #333;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
.indexDiv a {
margin-left: 20px;
}
.Readpage {
font-size: 14px;
padding: 0;
background: #d4eaf2;
height: 40px;
line-height: 40px;
text-align: center;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
* {
margin: 0;
padding: 0;
/* background-attachment: fixed; */
}
user agent stylesheet
p {
display: block;
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
}
.huyanon {
border: 1px solid #64c878;
box-shadow: 0 1px 2px #b9ecc4 inset, 0 -1px 0 #6c9f76 inset, 0 -2px 3px #b9ecc4 inset;
background: -webkit-linear-gradient(top, #90dfa2, #84d494);
background: -moz-linear-gradient(top, #90dfa2, #84d494);
background: linear-gradient(top, #90dfa2, #84d494);
}
.Readpage a {
font-size: 16px;
padding: 2px 2px;
line-height: 35px;
}
.lightoff, .huyanoff, .sizebgon {
border: 1px solid #333;
box-shadow: 0 1px 2px #8b8b8b inset, 0 -1px 0 #3d3d3d inset, 0 -2px 3px #8b8b8b inset;
background: -webkit-linear-gradient(top, #656565, #4c4c4c);
background: -moz-linear-gradient(top, #656565, #4a4a4a);
background: linear-gradient(top, #656565, #4a4a4a);
}
.button {
width: 40px;
line-height: 38px;
text-align: center;
font-weight: bold;
color: #fff;
text-shadow: 1px 1px 1px #333;
border-radius: 5px;
margin: 3px 0px 0px 0;
position: relative;
overflow: hidden;
}
a {
color: #4c6978;
text-decoration: none;
border: none;
cursor: pointer;
}
.lighton {
border: 1px solid #d2a000;
box-shadow: 0 1px 2px #fedd71 inset, 0 -1px 0 #a38b39 inset, 0 -2px 3px #fedd71 inset;
background: -webkit-linear-gradient(top, #fece34, #d8a605);
background: -moz-linear-gradient(top, #fece34, #d8a605);
background: linear-gradient(top, #fece34, #d8a605);
}
.screen_toolbar {
position: fixed;
width: 100%;
left: 0px;
bottom: 100px;
text-align: center;
}
</style>
</head>
<body id="read">
<div id="content">
<input type="hidden" id="bookIdHidden" th:value="${book.id}"/>
<input type="hidden" id="bookNameHidden" th:value="${book.bookName}"/>
<input type="hidden" id="contentIdHidden" th:value="${bookIndex.id}"/>
<input type="hidden" id="indexNameHidden" th:value="${bookIndex.indexName}"/>
<input type="hidden" id="indexNumHidden" th:value="${bookIndex.indexNum}"/>
<script>
var token = localStorage.getItem("token");
</script>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="width:10%;float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<a style="color: #ffffff;" th:href="'/book/'+ ${book.id} + '.html'"><b style="padding-left: 5%;float: left;width: 69%" class="line-limit-length" th:utext="${bookIndex.indexName}+' '+${book.bookName}"></b></a>
<div style="width:10%;float: right;margin-right: 10px"><a href="/">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i>
</a>
</div>
</div>
<p class="Readpage" style="background:#FFFFFF;padding:2px;">
<a id="lightdiv" class="button lighton" onclick="nr_setbg('light')">开灯</a>
<a id="huyandiv" class="button huyanon" onclick="nr_setbg('huyan')">护眼</a>&nbsp;&nbsp;&nbsp;&nbsp;
字体:<a id="fontbig" class="sizebg" onclick="nr_setbg('big')">大</a> <a id="fontmiddle" class="button sizebgon"
onclick="nr_setbg('middle')">中</a> <a
id="fontsmall" class="sizebg" onclick="nr_setbg('small')">小</a>
</p>
<div class="indexDiv" style="height: 42px;line-height: 42px;text-align:center;background: #f2f2f2">
<a th:href="${preBookIndexId!=0?'/book/'+book.id+'/'+preBookIndexId+'.html':'#'}">上一章</a>
<a th:href="'/book/indexList-'+${book.id}+'.html'">目录</a>
<a th:href="${nextBookIndexId!=0?'/book/'+book.id+'/'+nextBookIndexId+'.html':'#'}">下一章</a>
</div>
<!--<div id="screenInput" class="screen_toolbar" style="display: none">
<div style="height: 5px" class="layui-col-xs2 layui-col-sm3 layui-col-md3 layui-col-lg3"></div>
<div class="layui-col-xs6 layui-col-sm4 layui-col-md4 layui-col-lg4">
<input type="text" id="screenBulletText" required lay-verify="required" placeholder="请输入弹幕内容,右下角开关可控制弹幕是否开启" autocomplete="off"
class="layui-input">
</div>
<div class="layui-col-xs2 layui-col-sm1 layui-col-md1 layui-col-lg1">
<button class="layui-btn send">发送</button>
</div>
</div>
<form id="screenSwitch" class="layui-form">
<div class="layui-form-item" style="position: fixed;right: 0px;bottom: 100px" title="弹幕开关">
&lt;!&ndash; <label class="layui-form-label" style="opacity:0.5;font-weight: bold;color: red;">弹幕</label>&ndash;&gt;
<div class="layui-input-block">
<input class="clear" type="checkbox" name="switch" lay-skin="switch">
</div>
</div>
</form>-->
<div th:replace="common/js :: js">
</div>
<div id="chaptercontent" class="Readarea ReadAjax_content screen_container"
style="color: rgb(0, 0, 0); font-size: 25px;" th:if="${!needBuy}">
<p style="width:100%;text-alight:center; overflow: auto;-webkit-overflow-scrolling:touch;" >&nbsp;&nbsp;&nbsp;&nbsp;
<span
th:utext="${bookContent.content}"></span></p>
</div>
<div class="Readarea ReadAjax_content screen_container"
style="color: rgb(0, 0, 0); font-size: 10px;background-color: #fff" th:if="${needBuy}">
<h5>此章为VIP章节需要订阅后才能继续阅读</h5>
价格:<span style="color: red" th:text="${bookIndex.bookPrice}+'屋币(1元=100屋币)'"></span><br/>
<a href="javascript:buyBookIndex()" type="button" class="layui-btn layui-btn-sm layui-btn-radius">购买</a>
</div>
<div class="indexDiv" style="height: 42px;line-height: 42px;text-align:center;background: #f2f2f2">
<a th:href="${preBookIndexId!=0?'/book/'+book.id+'/'+preBookIndexId+'.html':'#'}">上一章</a>
<a th:href="'/book/indexList-'+${book.id}+'.html'">目录</a>
<a th:href="${nextBookIndexId!=0?'/book/'+book.id+'/'+nextBookIndexId+'.html':'#'}">下一章</a>
</div>
</div>
<div th:replace="common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<script>
var ua = navigator.userAgent;
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
isIphone =!ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
isAndroid = ua.match(/(Android)\s+([\d.]+)/),
isMobile = isIphone || isAndroid;
</script>
<script>
(function () {
//添加阅读记录
$.ajax({
type: "POST",
url: "/user/addReadHistory",
data: {'bookId': $("#bookIdHidden").val(), 'preContentId': $("#contentIdHidden").val()},
dataType: "json",
success: function (data) {
},
error: function () {
}
})
$("#content").css("min-height",($(window).height()-60)+"px");
})();
</script>
<script src="/js/read.js"></script>
<script language="javascript">getset()</script>
<script language="javascript">getset1()</script>
<script language="javascript">
var books = localStorage.getItem("historyBooks");
var item = parseInt($("#bookIdHidden").val());
if (books) {
var booksArr = JSON.parse(books);
if (booksArr.length >= 50) {
booksArr.splice(0, 1);
}
booksArr.remove(item);
booksArr[booksArr.length] = item;
} else {
var booksArr = [item];
}
localStorage.setItem("historyBooks", JSON.stringify(booksArr));//
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/search?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
function buyBookIndex(){
$.ajax({
type: "POST",
url: "/user/buyBookIndex",
data: {'bookId':$("#bookIdHidden").val(),"bookName":$("#bookNameHidden").val(),
"bookIndexId":$("#contentIdHidden").val(),"bookIndexName":$("#indexNameHidden").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
location.reload();
} else if(data.code == 1001){
//未登录
}else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
}
$.post("/book/addVisitCount", {"bookId": $("#bookIdHidden").val()}, function () {
});
</script>
</html>

View File

@ -0,0 +1,354 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:utext="${book.bookName}+'小说最新章节免费阅读和下载'"></title>
<meta name="keywords" th:content="${book.bookName}+','+${book.bookName}+'最新章节,'+${book.bookName}+'免费阅读,'+${book.bookName}+'TXT下载'">
<meta name="description"
th:content="${book.bookName}+'最新章节列表,'+${book.bookName}+'最新更新章节免费无广告无弹窗在线阅读,'+${book.bookName}+'小说TXT免费下载。'">
<div th:include="/common/css :: css"></div>
<style type="text/css">
.indexP p a{
color:#4c6978;
}
.tag-list {
padding-top: 0px;
padding-bottom: 20px;
position: fixed;
top:50px;
right: 0px;
width: 120px;
z-index:100000;
}
.tag-list .tag {
float: right;
width: 100%;
text-align: right;
margin-top: 5px;
}
.tag-list .tag a {
display: inline-block;
margin-right: 8px;
font-size: 12px;
}
.tag-list .highlight {
padding: 5px 9px;
border: 1px solid #f90;
color: #f90;
border-radius: 50px;
}
.tag-list .highlight .text {
color: #f90;
}
.tag-list .tag .text {
display: inline-block;
vertical-align: middle;
color: #f90;
}
ul, li {
padding: 0;
margin: 0;
list-style: none;
}
.tag-list .tag a {
display: inline-block;
margin-right: 8px;
font-size: 12px;
}
.tag-list .highlight .icn {
color: #f90;
}
.tag-list .tag .icn {
margin-right: 5px;
color: #ccc;
}
.tag-list .highlight .text {
padding-left: 3px;
color: #f90;
}
.tag-list .tag .text {
display: inline-block;
vertical-align: middle;
color: #f90;
}
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
</head>
<body>
<div id="content">
<ul class="tag-list clearfix" id="tagLi">
</ul>
<input type="hidden" id="bookIdHidden" th:value="${bookId}"/>
<input type="hidden" id="bookNamedHidden" th:value="${book.bookName}"/>
<input type="hidden" id="preContentId" th:value="${firstBookIndexId}"/>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon" th:utext="${book.bookName}"></b>
<div style="float: right;margin-right: 10px">
<a href="/"><i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i></a>
</div>
</div>
<div class="layui-row" style="background: #f2f2f2">
<div style="padding: 10px" class="layui-col-xs4 layui-col-sm2 layui-col-md2 layui-col-lg2">
<img style=" width:auto; height:auto; max-width:100%; max-height:100%;" th:src="${book.picUrl}"/>
</div>
<div style="position:relative;padding: 10px 20px" class="layui-col-xs8 layui-col-sm8 layui-col-md8 layui-col-lg8">
<a th:href="'javascript:searchBooks(\''+ ${book.authorName}+'\')'"><div style=";color: #4c6978;" th:utext="'作者'+ ${book.authorName}"></div></a>
<a th:href="'/book/book_ranking.html?catId='+${book.catId}"><div style="margin-top: 5px;color: #4c6978;" th:text="'类别'+ ${book.catName}"></div></a>
<div style="margin-top: 5px;color: #4c6978;" th:text="'状态'+ ${book.bookStatus==0?'连载':'完结'}"></div>
<div style="margin-top: 5px;color: #4c6978;">更新:<i th:text="${#dates.format(book.lastIndexUpdateTime, 'yy-MM-dd')}"></i></div>
<div style="margin-top: 5px;color: #4c6978;">评分:<i style="font-weight:bold;color: red" th:text="${book.score} + '分'"></i></div>
<div style="margin-top: 5px;color: #4c6978;">点击:<i style="font-weight:bold;color: red" th:text="${book.visitCount}"></i></div>
</div>
</div>
<div style="text-align: center;height: 45px;line-height: 45px">
<a th:href="'/book/'+${book.id}+'/'+${firstBookIndexId}+'.html'" type="button" class="layui-btn layui-btn-sm layui-btn-radius">开始阅读</a>
<!--
<button type="button" onclick="downloadFile()" class="layui-btn layui-btn-sm layui-btn-radius layui-bg-normal">下载TXT</button>
-->
</div>
<p style="line-height: 23px;padding: 10px;font-size: 14px;color: #4c6978;" th:utext="${book.bookDesc}">
</p>
<div class="layui-collapse">
<div class="layui-colla-item" >
<h2 class="layui-colla-title">
<span>最新章节</span>
<span style="margin-left: 30px">
更新: <i th:text="${#dates.format(book.lastIndexUpdateTime, 'yy-MM-dd HH:mm:ss')}"></i>
</span>
</h2>
<div class="layui-colla-content layui-show indexP layui-row" id="indexList">
</div>
</div>
</div>
<div style="height: 42px;color:#4c6978;line-height: 42px;padding-left: 30px;background: #f2f2f2" >
<a th:href="'/book/indexList-'+${book.id}+'.html'">查看完整目录</a>
</div>
<!--
<div style="position: fixed;top:0px;left:0px;z-index:-100;opacity: 0" th:utext="${attacDivForSearch}"></div>
-->
</div>
<div th:replace="/common/footer :: footer">
</div>
</body>
<div th:replace="/common/js :: js">
</div>
<script>
//查询是否在书架
$.ajax({
type: "GET",
url: "/user/queryIsInShelf",
data: {'bookId': $("#bookIdHidden").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
if (data.data) {
$("#cFavs").html("<button type=\"button\" id=\"cFavs\" class=\"layui-btn layui-btn-sm layui-btn-radius layui-btn-warm\">已在书架</button>");
}
} else if (data.code == 1001) {
//未登录
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
//查询最新目录集合
$.ajax({
type: "GET",
url: "/book/queryNewIndexList",
data: {'bookId': $("#bookIdHidden").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
var indexListHtml = "";
for(var i = 0 ; i < data.data.length ; i++){
var bookIndex = data.data[i];
indexListHtml+=("<p class=\"line-limit-length layui-col-xs12 layui-col-sm4 layui-col-md3 layui-col-lg2\" style=\"padding-left:10px;height: 50px;line-height: 50px;\"><a href=\"/book/"+$("#bookIdHidden").val()+"/"+bookIndex.id+".html\">"+bookIndex.indexName+"</a></p>");
}
$("#indexList").html(indexListHtml);
} else if (data.code == 1001) {
//未登录
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
function addInShell() {
$.ajax({
type: "POST",
url: "/user/addToBookShelf",
data: {'bookId': $("#bookIdHidden").val(), 'preContentId': $("#preContentId").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
$("#cFavs").html("<button type=\"button\" id=\"cFavs\" class=\"layui-btn layui-btn-sm layui-btn-radius layui-btn-warm\">已在书架</button>");
} else if (data.code == 1001) {
//未登录
location.href = '/user/login.html?originUrl=' + decodeURIComponent(location.href);
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
}
$("#content").css("min-height",($(window).height()-60)+"px");
function downloadFile() {
var fileUrl = '/book/download?bookId='+$("#bookIdHidden").val()+'&bookName='+$("#bookNamedHidden").val();
window.location.href=fileUrl;
}
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
function addToCollect(){
var token = localStorage.getItem("token");
if(token) {
$.get("/user/addToCollect",{"bookId":$("#bookIdHidden").val(),"token":token},function(data){
layer.alert(data.desc);
if(data.code == 1) {
$('#collectButton').unbind("click");
$("#collectButton").text("撤下书架");
$("#collectButton").click(function () {
cancelToCollect();
});
}
});
}else{
window.location.href = "/user/login.html?bookId="+$("#bookIdHidden").val();
}
}
function cancelToCollect(){
var token = localStorage.getItem("token");
if(token) {
$.get("/user/cancelToCollect",{"bookId":$("#bookIdHidden").val(),"token":token},function(data){
layer.alert(data.desc);
if(data.code == 1) {
$('#collectButton').unbind("click");
$("#collectButton").text("加入书架");
$("#collectButton").click(function () {
addToCollect();
});
}
});
}else{
window.location.href = "/user/login.html?bookId="+$("#bookIdHidden").val();
}
}
function searchBooks(keyword) {
window.location.href = "/book/book_ranking.html?keyword=" + encodeURI(keyword);
}
$.post("/book/addVisitCount", {"bookId": $("#bookIdHidden").val()}, function () {
});
</script>
</html>

View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:utext="${book.bookName}+'最新免费章节目录列表'"></title>
<meta name="keywords" th:content="${book.bookName}+','+${book.bookName}+'最新章节'">
<meta name="description"
th:content="${book.bookName}+'最新章节列表,'+${book.bookName}+'最新更新章节免费无广告无弹窗在线阅读TXT下载。'">
</div>
<div th:include="/common/css :: css"></div>
<style type="text/css">
.indexP p a {
color: #4c6978;
}
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
</div>
</head>
<body>
<div id="content">
<input type="hidden" id="bookIdHidden" th:value="${book.id}"/>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<a style="color: #ffffff;" th:href="'/book/'+ ${book.id} + '.html'"><b class="layui-icon" th:utext="${book.bookName}"></b></a>
<div style="float: right;margin-right: 10px">
<a href="/"><i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i></a>
</div>
</div>
<p style="height: 30px;line-height: 30px;padding: 10px">
<a href="#buttom" style="color: red">&nbsp;&nbsp;↓直达页面底部</a>
</p>
<div class="layui-colla-content layui-show indexP layui-row">
<p class="line-limit-length layui-col-xs12 layui-col-sm4 layui-col-md3 layui-col-lg2" style="padding-left:10px;height: 50px;line-height: 50px;" th:each="index : ${bookIndexList}">
<a th:href="'/book/'+${index.bookId}+'/'+${index.id}+'.html'" th:utext="${index.indexName}">
</a>
</p>
</div>
</div>
<div th:replace="/common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="/common/js :: js">
</div>
<script>
$("#content").css("min-height",($(window).height()-60)+"px");
$.get("/book/addVisit",{"bookId":$("#bookIdHidden").val()},function(){});
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,320 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:text="#{website.name}+'列表'"></title>
<meta name="keywords"
th:content="#{website.name}+',精品小说,弹幕网站,弹幕,弹幕小说网站,免费小说,小说阅读,小说排行,轻小说,txt小说下载,电子书下载,动漫轻小说,日本轻小说'">
<meta name="description"
th:content="#{website.name}+'是国内优秀的小说弹幕网站,'+#{website.name}+'提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读和TXT小说下载,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜,致力于无广告无弹窗的小说阅读环境。'">
<div th:include="/common/css :: css"></div>
</div>
<style type="text/css">
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indexP p a {
color: #4c6978;
}
.Readarea {
font-size: 18px;
line-height: 35px;
padding: 10px;
color: #333;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
.indexDiv a {
margin-left: 20px;
}
img {
width: 130px;
height: 180px;
}
</style>
</head>
<body>
<input type="hidden" id="limit" th:value="${limit}"/>
<input type="hidden" id="curr" th:value="${curr}"/>
<input type="hidden" id="total" th:value="${total}"/>
<input type="hidden" id="ids" th:value="${ids}"/>
<input type="hidden" id="bookStatus" th:value="${bookStatus}"/>
<input type="hidden" id="token" th:value="${token}"/>
<input type="hidden" id="keyword" th:value="${keyword}"/>
<input type="hidden" id="catId" th:value="${catId}"/>
<input type="hidden" id="sortBy" th:value="${sortBy}"/>
<input type="hidden" id="sort" th:value="${sort}"/>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon">小说列表</b>
<div style="float: right;margin-right: 10px">
<a href="/"><i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i></a>
</div>
</div>
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs10 layui-col-sm10 layui-col-md11 layui-col-lg11" style="padding-top:1%">
<input id="title" type="text" name="title" required lay-verify="required" placeholder="请输入书名·作者"
autocomplete="off"
class="layui-input" th:value="${keyword}">
</div>
<div class="layui-col-xs1" style="padding: 1%">
<button onclick="search(1,20)" class="layui-btn" lay-submit lay-filter="formDemo">搜索</button>
</div>
</div>
</div>
<div id="bookList">
</div>
<div id="books" style="text-align: center"></div>
<div th:replace="/common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="/common/js :: js"></div>
<script>
var catId = getQueryVariable("catId");
var bookStatus = getQueryVariable("bookStatus");
var sortBy = getQueryVariable("sortBy");
var keyword = getQueryVariable("keyword");
if(keyword != false){
$("#title").val(decodeURI(keyword));
}else{
keyword = "";
}
search(1,20);
function search(curr,limit) {
var searchData = {};
searchData.curr = curr;
searchData.limit = limit;
keyword = $("#title").val();
if(catId != false){
searchData.catId = catId;
}
if(bookStatus != false){
searchData.bookStatus = bookStatus;
}
if(sortBy != false){
searchData.sort = sortBy;
}else if(!keyword){
sortBy = "last_index_update_time";
}
if(keyword){
searchData.keyword = keyword;
}
$.ajax({
type: "GET",
url: "/book/searchByPage",
data: searchData,
dataType: "json",
success: function (data) {
if (data.code == 200) {
var bookList = data.data.list;
var bookListHtml = "";
for (var i = 0; i < bookList.length; i++) {
var book = bookList[i];
/*var end = book.bookDesc.indexOf("<");
if(end != -1) {
book.bookDesc = book.bookDesc.substring(0,end);
}*/
if(book.bookDesc){
book.bookDesc = book.bookDesc.replace(/<[^>]+>/g,"").replace(/\s+/g,"").replace(/&nbsp;/g,"");
}
bookListHtml += ("<div class=\"layui-row\" style=\"margin-bottom:10px;padding:10px;background: #f2f2f2\">\n" +
" <a href=\"/book/"+book.id+".html\">\n" +
" <div class=\"layui-col-xs6 layui-col-sm3 layui-col-md2 layui-col-lg2\" style=\"text-align: center\">\n" +
" <img width='150' height='180' align=\"center\"\n" +
" src=\""+book.picUrl+"\"/>\n" +
"\n" +
" </div>\n" +
" </a>\n" +
" <div style=\"padding: 10px\" class=\"layui-col-xs6 layui-col-sm8 layui-col-md8 layui-col-lg8\">\n" +
" <a href=\"/book/"+book.id+".html\">\n" +
" <div class=\"line-limit-length\" style=\";color: #4c6978;font-weight: bold;font-size: 15px\">"+book.bookName+"</div>\n" +
" </a>\n" +
" <div style=\";color: #4c6978;float: right;\"><i style=\"color: red\"></i></div>\n" +
" <a href=\"/book/book_ranking.html?keyword="+encodeURI(book.authorName)+"\">\n" +
" <div style=\";color: #4c6978;\" class=\"line-limit-length\">作者:"+book.authorName+"</div>\n" +
" </a>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">类别:"+book.catName+"</div>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">状态:"+(book.bookStatus==0?'连载':'完结')+"</div>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">更新:<i>"+book.lastIndexUpdateTime.substr(0,11)+"</i>\n" +
" </div>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">简介:"+(book.bookDesc?(book.bookDesc.length>20?(book.bookDesc.substr(0,20)+"..."):book.bookDesc):book.bookDesc)+"</div>\n" +
"\n" +
"\n" +
" </div>\n" +
"\n" +
" </div>");
}
$("#bookList").html(bookListHtml);
layui.use('laypage', function () {
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
elem: 'books' //注意,这里的 test1 是 ID不用加 # 号
, count: data.data.total //数据总数,从服务端得到,
, curr: data.data.pageNum
, limit: data.data.pageSize
, jump: function (obj, first) {
//obj包含了当前分页的所有参数比如
console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。
console.log(obj.limit); //得到每页显示的条数
//首次不执行
if (!first) {
search(obj.curr, obj.limit);
} else {
}
}
});
});
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
}
function searchByAllCondition(curr, limit, newKeyword) {
var toUrl = "/book/search?curr=" + curr + "&limit=" + limit;
var ids = $("#ids").val();
if (ids) {
toUrl += ("&historyBookIds=" + ids);
}
var token = $("#token").val();
if (token) {
toUrl += ("&token=" + token);
}
var keyword = $("#keyword").val();
if (newKeyword) {
toUrl += encodeURI("&keyword=" + newKeyword);
} else if (keyword) {
toUrl += encodeURI("&keyword=" + keyword);
}
var bookStatus = $("#bookStatus").val();
if (bookStatus) {
toUrl += ("&bookStatus=" + bookStatus);
}
var catId = $("#catId").val();
if (catId) {
toUrl += ("&catId=" + catId);
}
var sortBy = $("#sortBy").val();
if (sortBy) {
toUrl += ("&sortBy=" + sortBy);
}
var sort = $("#sort").val();
if (sort) {
toUrl += ("&sort=" + sort);
}
window.location.href = toUrl;
}
function searchBooks() {
var keywords = $("#title").val();
$("#keyword").val("");
searchByAllCondition(1, 20, keywords);
}
</script>
<script>
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/search?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>小说提交</title>
<div th:include="common/css :: css"></div>
</head>
<body id="read" >
</div>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon">单本小说提交</b>
<div style="float: right;margin-right: 10px"><a href="/">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i>
</a>
</div>
</div>
<div style="height: 800px;padding: 20px;border: 1px solid #eee;">
<form class="layui-form" action="">
<div class="layui-form-item">
<label class="layui-form-label">详情页Url:</label>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md3 layui-col-lg1" >
<input type="text" id="bookUrl" name="bookUrl" required lay-verify="required" placeholder="请输入源站小说详情页Url" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">小说名:</label>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md3 layui-col-lg1" >
<input type="text" id="bookName" name="bookName" required lay-verify="required" placeholder="请输入小说名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">小说评分:</label>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md3 layui-col-lg1">
<input type="number" id="score" name="score" required lay-verify="required" placeholder="请输入小说评分" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
<div th:replace="common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="common/js :: js"></div>
<script>
//Demo
layui.use('form', function(){
var form = layui.form;
//监听提交
form.on('submit(formDemo)', function(){
$.post("/book/submit",{"bookUrl":$("#bookUrl").val(),"bookName":$("#bookName").val(),"score":$("#score").val()},function (data) {
if(data.code == 1 ){
layer.alert("提交成功任务排队中请过一段时间后再搜索查看");
}else{
layer.alert("提交失败");
}
});
return false;
});
});
</script>
</html>

View File

@ -0,0 +1,24 @@
<div th:fragment="css">
<link rel="stylesheet" href="/layui/css/layui.css">
<style type="text/css">
.app {
display: none;
}
@media (max-width: 360px) {
.app {
display: block !important;
}
}
.pc {
display: block;
}
@media (max-width: 360px) {
.pc {
display: none;
}
}
</style>
</div>

View File

@ -0,0 +1,11 @@
<div th:fragment="footer" style="height: 60px;line-height: 60px;text-align: center" class="layui-footer footer footer-demo layui-bg-cyan">
<!--<a href="/mobile/book/searchSoftBook.html" style="font-size: 14px;color: #92B8B1;">轻小说</a>
<a href="/mobile/book/searchSoftBook.html?catId=9" style="font-size: 14px;color: #92B8B1;margin-left: 8px">漫画</a>-->
<a href="/?to=mobile" style="font-size: 14px;color: #92B8B1;margin-left: 8px">手机站</a>
<!--<a href="https://www.zinglizingli.xyz/me/index.html" style="font-size: 14px;color: #92B8B1;margin-left: 8px">开发者</a>-->
<div style="float: right"><a href="#top"><i class="layui-icon"
style="margin-right:15px;font-size: 30px;color:#92B8B1 ">&#xe604;</i></a>
</div>
</div>

View File

@ -0,0 +1,3 @@
<script th:fragment="js" src="/js/jquery-1.9.1.js"></script>
<script th:fragment="js" src="/js/common.js"></script>
<script th:fragment="js" src="/layui/layui.all.js"></script>

View File

@ -0,0 +1,388 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:text="#{website.name}"></title>
<meta name="keywords" th:content="#{website.name}+',精品小说,弹幕网站,弹幕,弹幕小说网站,免费小说,小说阅读,小说排行,轻小说,txt小说下载,电子书下载,动漫轻小说,日本轻小说'">
<meta name="description"
th:content="#{website.name}+'是国内优秀的小说弹幕网站,'+#{website.name}+'提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读和TXT小说下载,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜,致力于无广告无弹窗的小说阅读环境。'">
<meta property="og:type" content="novel_index"/>
<meta property="og:title" th:content="#{website.name}"/>
<meta property="og:description"
th:content="#{website.name}+'是国内优秀的小说弹幕网站,'+#{website.name}+'提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读和TXT小说下载,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜,致力于无广告无弹窗的小说阅读环境。'"/>
<div th:include="/common/css :: css"></div>
<style>
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.layui-nav .layui-nav-item {
position: relative;
display: inline-block;
vertical-align: middle;
line-height: 50px;
}
body ul.layui-nav li.layui-nav-item a {
display: block;
transition: all .3s;
-webkit-transition: all .3s;
}
</style>
</head>
<body>
<!-- 你的HTML代码 -->
<a name="top"></a>
<ul class="layui-nav app" lay-filter="" style="display:none;padding:0 10px;text-align: center">
<li class="layui-nav-item"><a>分类</a>
<dl class="layui-nav-child">
<dd><a href="/book/book_ranking.html?catId=1&sort=last_index_update_time">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=2&sort=last_index_update_time">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=3&sort=last_index_update_time">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=4&sort=last_index_update_time">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=6&sort=last_index_update_time">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=5&sort=last_index_update_time">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=7&sort=last_index_update_time">女频小说</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a>全本</a>
<dl class="layui-nav-child">
<dd><a href="/book/book_ranking.html?bookStatus=1">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=7">女频小说</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a>排行</a>
<dl class="layui-nav-child">
<dd><a href="/book/book_ranking.html?sortBy=visit_count">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=7">女频小说</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav pc" lay-filter="" style="padding:0 36px;text-align: center">
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=1&sort=last_index_update_time">玄幻小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=2&sort=last_index_update_time">修真小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=3&sort=last_index_update_time">都市小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=4&sort=last_index_update_time">历史小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=6&sort=last_index_update_time">网游小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=5&sort=last_index_update_time">科幻小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=7&sort=last_index_update_time">女频小说</a></li>
<li class="layui-nav-item"><a>完本小说</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/book_ranking.html?bookStatus=1">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=7">女频小说</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a>小说排行</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/book_ranking.html?sortBy=visit_count">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=7">女频小说</a></dd>
</dl>
</li>
</ul>
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs10 layui-col-sm10 layui-col-md11 layui-col-lg11" style="padding-top:1%">
<input id="title" type="text" name="title" required lay-verify="required" placeholder="请输入书名·作者"
autocomplete="off"
class="layui-input">
</div>
<div class="layui-col-xs1" style="padding: 1%">
<button onclick="searchBooks()" class="layui-btn" lay-submit lay-filter="formDemo">搜索</button>
</div>
</div>
</div>
<div style="height: 1px" class="layui-col-lg1"></div>
<div class="layui-collapse layui-col-lg10">
<div class="layui-colla-item">
<h2 class="layui-colla-title">本站推荐</h2>
<div class="layui-colla-content layui-show">
<div class="layui-container" style="padding: 0px">
<div class="layui-row" style="text-align: center" id="currentWeek">
</div>
</div>
</div>
</div>
<div class="layui-colla-item">
<h2 class="layui-colla-title">热门小说推荐</h2>
<div class="layui-colla-content layui-show">
<div class="layui-container">
<div class="layui-row" id="hotRecBooks">
<!--<div th:each="hotBook : ${hotBooks}" style="margin-top: 1%"
class="layui-col-xs12 layui-col-sm6 layui-col-md6 layui-col-lg6">
<a th:href="'/book/'+${hotBook.id}+'.html'">
<div class="layui-col-xs5 layui-col-sm3 layui-col-md3 layui-col-lg3">
<img style=" width:100px; height:125px;"
th:src="${hotBook.picUrl}"/>
</div>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md7 layui-col-lg7"
style="float: left;padding-right: 10px">
<div><b th:text="${hotBook.bookName}"></b></div>
<div class="layui-col-xs8 layui-col-sm9 layui-col-md10 layui-col-lg10"
th:text="'作者'+ ${hotBook.author}"></div>
<div class="layui-col-xs3 layui-col-sm2 layui-col-md1 layui-col-lg1" style="text-align: right;">
<b><i style="color: red"
th:text="${hotBook.score} + '分'"></i></b></div>
</div>
<div class="layui-elip layui-col-xs12 layui-col-sm9 layui-col-md10 layui-col-lg10 layui-col-sm9 layui-col-md10 layui-col-lg10"
th:text="${hotBook.bookDesc}">
</div>
</a>
</div>-->
</div>
</div>
</div>
</div>
</div>
</div>
<div style="clear: both"></div>
<div style="height: 1px" class="layui-col-lg1"></div>
<div class="layui-colla-item layui-col-lg10"
style="border-width: 1px;border-style: solid;border-radius: 2px;border-top-width: 0px"><a
href="javascript:moreNewBooks()">
<h2 class="layui-colla-title">最近更新小说
<div style="float: right; margin-right: 20px"><i style="font-size: 14px;"
class="layui-icon">更多&#xe65b;</i>
</div>
</h2>
</a>
<div class="layui-colla-content layui-show">
<div class="layui-container" style="padding-left: 2px;padding-right: 5px">
<div class="layui-row" id="updateRankBooks">
</div>
</div>
</div>
</div>
</div>
<div style="clear: both"></div>
<div th:replace="/common/footer :: footer">
</div>
<div th:replace="/common/js :: js">
</div>
<script src="/js/wap_collect.js"></script>
<script>
//加载首页书籍设置数据
$.ajax({
type: "GET",
url: "/book/listBookSetting",
data: {},
dataType: "json",
success: function (data) {
if (data.code == 200) {
//本周强推
var rightListBooks = data.data[2];
var rightListBooksHtml = "";
for (var i = 0; i < 3; i++) {
var rightListBook = rightListBooks[i];
var classHtml = "";
if (i == 0) {
classHtml = "on";
}
if (i < 3) {
classHtml += (" num" + (i + 1));
}
rightListBooksHtml += (" <span>\n" +
" <a href=\"/book/"+rightListBook.bookId+".html\">\n" +
" <div style=\"padding: 1%\" class=\"layui-col-xs4 layui-col-sm4 layui-col-md4 layui-col-lg4\">\n" +
" <img style=\" width:80%; height:auto; max-width:100%; max-height:100%;\"\n" +
" src=\""+rightListBook.picUrl+"\"/>\n" +
"\n" +
" <br/>\n" +
" <span>"+rightListBook.bookName+"</span>\n" +
"\n" +
" </div>\n" +
" </a>\n" +
" </span>");
}
$("#currentWeek").html(rightListBooksHtml);
//热门推荐
var hotRecBooks = data.data[3];
var hotRecBooksHtml = "";
for (var i = 0; i < 6; i++) {
var hotRecBook = hotRecBooks[i];
if(hotRecBook.bookDesc){
hotRecBook.bookDesc = hotRecBook.bookDesc.replace(/<[^>]+>/g,"").replace(/\s+/g,"");
}
hotRecBooksHtml += ("<div style=\"margin-bottom: 5px\" class=\"layui-col-xs12 layui-col-sm6 layui-col-md4 layui-col-lg4\">\n" +
" <a href=\"/book/"+hotRecBook.bookId+".html\">\n" +
" <div class=\"layui-col-xs5 layui-col-sm4 layui-col-md4 layui-col-lg4\" >\n" +
" <img style=\" width:100px; height:125px;\"\n" +
" src=\""+hotRecBook.picUrl+"\"/>\n" +
"\n" +
" </div>\n" +
" <div class=\"layui-col-xs5 layui-col-sm6 layui-col-md6 layui-col-lg6\">\n" +
" <ul>\n" +
" <li class=\"line-limit-length\" style=\"font-weight: bold\">"+hotRecBook.bookName+"</li>\n" +
" <li>作者:"+hotRecBook.authorName+"</li>\n" +
" <li style=\"width: 180px;height:40px;overflow: hidden\">简介:  "+hotRecBook.bookDesc+"" +
" </ul>\n" +
" </div>\n" +
" <div style=\"font-style: italic;color: red\"\n" +
" class=\"layui-col-xs2 layui-col-sm2 layui-col-md2 layui-col-lg2\"></div>\n" +
" </a>\n" +
" </div>");
}
$("#hotRecBooks").html(hotRecBooksHtml);
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
//更新榜单查询
$.ajax({
type: "GET",
url: "/book/listUpdateRank",
data: {},
dataType: "json",
success: function (data) {
if (data.code == 200) {
var updateRankBooks = data.data;
var updateRankBookHtml = "";
for (var i = 0; i < 10; i++) {
var updateRankBook = updateRankBooks[i];
if(updateRankBook.bookDesc){
updateRankBook.bookDesc = updateRankBook.bookDesc.replace(/<[^>]+>/g,"").replace(/\s+/g,"");
}
updateRankBookHtml += ("<div style=\"padding-bottom: 30px\"\n" +
" class=\"layui-col-xs12 layui-col-sm6 layui-col-md6 layui-col-lg6\">\n" +
"\n" +
" <a href=\"/book/"+updateRankBook.id+".html\">\n" +
" <div class=\"line-limit-length layui-col-xs8 layui-col-sm6 layui-col-md6 layui-col-lg6\"><b>"+(i+1)+"."+updateRankBook.bookName+"</b> - <span class=\"layui-elip\">"+updateRankBook.authorName+"</span>\n" +
" </div>\n" +
" <div class=\"layui-col-sm3 layui-col-md3 layui-col-lg3\"\n" +
" style=\"color: #FF5722;float: right;margin-right:5px\"><i>"+updateRankBook.lastIndexUpdateTime+"</i></div>\n" +
"\n" +
" <div style=\"clear: both\"></div>\n" +
" <div style=\"padding-left: 5px;padding-top: 5px\"\n" +
" class=\"layui-elip layui-col-md11 layui-col-sm11 layui-col-lg11\">简介:  "+updateRankBook.bookDesc+"" +
" </div></a>\n" +
" </div>");
}
$("#updateRankBooks").html(updateRankBookHtml);
} else {
layer.alert(data.msg);
}
}
,
error: function () {
layer.alert('网络异常');
}
})
function moreNewBooks(event) {
window.location.href = "/book/book_ranking.html?sortBy=last_index_update_time";
}
function searchBooks() {
var keywords = $("#title").val();
window.location.href = "/book/book_ranking.html?keyword=" + encodeURI(keywords);
}
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/book_ranking.html?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,364 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta th:if="${catId == 9}" name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=1">
<meta th:if="${catId != 9}" name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:utext="${book.bookName}+${bookIndex.indexName}"></title>
<meta name="keywords" th:content="${book.bookName}+','+${bookIndex.indexName}">
<meta name="description"
th:content="${book.bookName}+'最新更新章节免费在线阅读TXT下载'">
<div th:include="mobile/common/css :: css"></div>
<script type="text/javascript">
function reinitIframe(){
var iframe = document.getElementById("frame_content");
try{
iframe.height =  iframe.contentWindow.document.documentElement.scrollHeight;
}catch (ex){}
}
window.setInterval("reinitIframe()", 200);
</script>
<script th:fragment="js" src="/mobile/js/jquery-1.9.1.js"></script>
<script th:fragment="js" src="/mobile/layui/layui.all.js"></script>
</div>
<style type="text/css">
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indexP p a {
color: #4c6978;
}
.Readarea {
font-size: 18px;
line-height: 35px;
padding: 10px;
color: #333;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
.indexDiv a {
margin-left: 20px;
}
.Readpage {
font-size: 14px;
padding: 0;
background: #d4eaf2;
height: 40px;
line-height: 40px;
text-align: center;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
* {
margin: 0;
padding: 0;
/* background-attachment: fixed; */
}
user agent stylesheet
p {
display: block;
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
}
.huyanon {
border: 1px solid #64c878;
box-shadow: 0 1px 2px #b9ecc4 inset, 0 -1px 0 #6c9f76 inset, 0 -2px 3px #b9ecc4 inset;
background: -webkit-linear-gradient(top, #90dfa2, #84d494);
background: -moz-linear-gradient(top, #90dfa2, #84d494);
background: linear-gradient(top, #90dfa2, #84d494);
}
.Readpage a {
font-size: 16px;
padding: 2px 2px;
line-height: 35px;
}
.lightoff, .huyanoff, .sizebgon {
border: 1px solid #333;
box-shadow: 0 1px 2px #8b8b8b inset, 0 -1px 0 #3d3d3d inset, 0 -2px 3px #8b8b8b inset;
background: -webkit-linear-gradient(top, #656565, #4c4c4c);
background: -moz-linear-gradient(top, #656565, #4a4a4a);
background: linear-gradient(top, #656565, #4a4a4a);
}
.button {
width: 40px;
line-height: 38px;
text-align: center;
font-weight: bold;
color: #fff;
text-shadow: 1px 1px 1px #333;
border-radius: 5px;
margin: 3px 0px 0px 0;
position: relative;
overflow: hidden;
}
a {
color: #4c6978;
text-decoration: none;
border: none;
cursor: pointer;
}
.lighton {
border: 1px solid #d2a000;
box-shadow: 0 1px 2px #fedd71 inset, 0 -1px 0 #a38b39 inset, 0 -2px 3px #fedd71 inset;
background: -webkit-linear-gradient(top, #fece34, #d8a605);
background: -moz-linear-gradient(top, #fece34, #d8a605);
background: linear-gradient(top, #fece34, #d8a605);
}
.screen_toolbar {
position: fixed;
width: 100%;
left: 0px;
bottom: 100px;
text-align: center;
}
</style>
</head>
<body id="read">
<div id="content">
<input type="hidden" id="bookIdHidden" th:value="${book.id}"/>
<input type="hidden" id="bookNameHidden" th:value="${book.bookName}"/>
<input type="hidden" id="contentIdHidden" th:value="${bookIndex.id}"/>
<input type="hidden" id="indexNameHidden" th:value="${bookIndex.indexName}"/>
<input type="hidden" id="indexNumHidden" th:value="${bookIndex.indexNum}"/>
<script>
var token = localStorage.getItem("token");
</script>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="width:10%;float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<a style="color: #ffffff;" th:href="'/book/'+ ${book.id} + '.html'"><b style="padding-left: 5%;float: left;width: 69%" class="line-limit-length" th:utext="${bookIndex.indexName}+' '+${book.bookName}"></b></a>
<div style="width:10%;float: right;margin-right: 10px"><a href="/">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i>
</a>
</div>
</div>
<p class="Readpage" style="background:#FFFFFF;padding:2px;">
<a id="lightdiv" class="button lighton" onclick="nr_setbg('light')">开灯</a>
<a id="huyandiv" class="button huyanon" onclick="nr_setbg('huyan')">护眼</a>&nbsp;&nbsp;&nbsp;&nbsp;
字体:<a id="fontbig" class="sizebg" onclick="nr_setbg('big')">大</a> <a id="fontmiddle" class="button sizebgon"
onclick="nr_setbg('middle')">中</a> <a
id="fontsmall" class="sizebg" onclick="nr_setbg('small')">小</a>
</p>
<div class="indexDiv" style="height: 42px;line-height: 42px;text-align:center;background: #f2f2f2">
<a th:href="${preBookIndexId!=0?'/book/'+book.id+'/'+preBookIndexId+'.html':'#'}">上一章</a>
<a th:href="'/book/indexList-'+${book.id}+'.html'">目录</a>
<a th:href="${nextBookIndexId!=0?'/book/'+book.id+'/'+nextBookIndexId+'.html':'#'}">下一章</a>
</div>
<!--<div id="screenInput" class="screen_toolbar" style="display: none">
<div style="height: 5px" class="layui-col-xs2 layui-col-sm3 layui-col-md3 layui-col-lg3"></div>
<div class="layui-col-xs6 layui-col-sm4 layui-col-md4 layui-col-lg4">
<input type="text" id="screenBulletText" required lay-verify="required" placeholder="请输入弹幕内容,右下角开关可控制弹幕是否开启" autocomplete="off"
class="layui-input">
</div>
<div class="layui-col-xs2 layui-col-sm1 layui-col-md1 layui-col-lg1">
<button class="layui-btn send">发送</button>
</div>
</div>
<form id="screenSwitch" class="layui-form">
<div class="layui-form-item" style="position: fixed;right: 0px;bottom: 100px" title="弹幕开关">
&lt;!&ndash; <label class="layui-form-label" style="opacity:0.5;font-weight: bold;color: red;">弹幕</label>&ndash;&gt;
<div class="layui-input-block">
<input class="clear" type="checkbox" name="switch" lay-skin="switch">
</div>
</div>
</form>-->
<div th:replace="mobile/common/js :: js">
</div>
<div id="chaptercontent" class="Readarea ReadAjax_content screen_container"
style="color: rgb(0, 0, 0); font-size: 25px;" th:if="${!needBuy}">
<p style="width:100%;text-alight:center; overflow: auto;-webkit-overflow-scrolling:touch;" >&nbsp;&nbsp;&nbsp;&nbsp;
<span
th:utext="${bookContent.content}"></span></p>
</div>
<div class="Readarea ReadAjax_content screen_container"
style="color: rgb(0, 0, 0); font-size: 10px;background-color: #fff" th:if="${needBuy}">
<h5>此章为VIP章节需要订阅后才能继续阅读</h5>
价格:<span style="color: red" th:text="${bookIndex.bookPrice}+'屋币(1元=100屋币)'"></span><br/>
<a href="javascript:buyBookIndex()" type="button" class="layui-btn layui-btn-sm layui-btn-radius">购买</a>
</div>
<div class="indexDiv" style="height: 42px;line-height: 42px;text-align:center;background: #f2f2f2">
<a th:href="${preBookIndexId!=0?'/book/'+book.id+'/'+preBookIndexId+'.html':'#'}">上一章</a>
<a th:href="'/book/indexList-'+${book.id}+'.html'">目录</a>
<a th:href="${nextBookIndexId!=0?'/book/'+book.id+'/'+nextBookIndexId+'.html':'#'}">下一章</a>
</div>
</div>
<div th:replace="mobile/common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<script>
var ua = navigator.userAgent;
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
isIphone =!ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
isAndroid = ua.match(/(Android)\s+([\d.]+)/),
isMobile = isIphone || isAndroid;
</script>
<script>
(function () {
//添加阅读记录
$.ajax({
type: "POST",
url: "/user/addReadHistory",
data: {'bookId': $("#bookIdHidden").val(), 'preContentId': $("#contentIdHidden").val()},
dataType: "json",
success: function (data) {
},
error: function () {
}
})
$("#content").css("min-height",($(window).height()-60)+"px");
})();
</script>
<script src="/mobile/js/read.js"></script>
<script language="javascript">getset()</script>
<script language="javascript">getset1()</script>
<script language="javascript">
var books = localStorage.getItem("historyBooks");
var item = parseInt($("#bookIdHidden").val());
if (books) {
var booksArr = JSON.parse(books);
if (booksArr.length >= 50) {
booksArr.splice(0, 1);
}
booksArr.remove(item);
booksArr[booksArr.length] = item;
} else {
var booksArr = [item];
}
localStorage.setItem("historyBooks", JSON.stringify(booksArr));//
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/search?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
function buyBookIndex(){
$.ajax({
type: "POST",
url: "/user/buyBookIndex",
data: {'bookId':$("#bookIdHidden").val(),"bookName":$("#bookNameHidden").val(),
"bookIndexId":$("#contentIdHidden").val(),"bookIndexName":$("#indexNameHidden").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
location.reload();
} else if(data.code == 1001){
//未登录
}else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
}
$.post("/book/addVisitCount", {"bookId": $("#bookIdHidden").val()}, function () {
});
</script>
</html>

View File

@ -0,0 +1,354 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:utext="${book.bookName}+'小说最新章节免费阅读和下载'"></title>
<meta name="keywords" th:content="${book.bookName}+','+${book.bookName}+'最新章节,'+${book.bookName}+'免费阅读,'+${book.bookName}+'TXT下载'">
<meta name="description"
th:content="${book.bookName}+'最新章节列表,'+${book.bookName}+'最新更新章节免费无广告无弹窗在线阅读,'+${book.bookName}+'小说TXT免费下载。'">
<div th:include="mobile/common/css :: css"></div>
<style type="text/css">
.indexP p a{
color:#4c6978;
}
.tag-list {
padding-top: 0px;
padding-bottom: 20px;
position: fixed;
top:50px;
right: 0px;
width: 120px;
z-index:100000;
}
.tag-list .tag {
float: right;
width: 100%;
text-align: right;
margin-top: 5px;
}
.tag-list .tag a {
display: inline-block;
margin-right: 8px;
font-size: 12px;
}
.tag-list .highlight {
padding: 5px 9px;
border: 1px solid #f90;
color: #f90;
border-radius: 50px;
}
.tag-list .highlight .text {
color: #f90;
}
.tag-list .tag .text {
display: inline-block;
vertical-align: middle;
color: #f90;
}
ul, li {
padding: 0;
margin: 0;
list-style: none;
}
.tag-list .tag a {
display: inline-block;
margin-right: 8px;
font-size: 12px;
}
.tag-list .highlight .icn {
color: #f90;
}
.tag-list .tag .icn {
margin-right: 5px;
color: #ccc;
}
.tag-list .highlight .text {
padding-left: 3px;
color: #f90;
}
.tag-list .tag .text {
display: inline-block;
vertical-align: middle;
color: #f90;
}
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
</head>
<body>
<div id="content">
<ul class="tag-list clearfix" id="tagLi">
</ul>
<input type="hidden" id="bookIdHidden" th:value="${bookId}"/>
<input type="hidden" id="bookNamedHidden" th:value="${book.bookName}"/>
<input type="hidden" id="preContentId" th:value="${firstBookIndexId}"/>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon" th:utext="${book.bookName}"></b>
<div style="float: right;margin-right: 10px">
<a href="/"><i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i></a>
</div>
</div>
<div class="layui-row" style="background: #f2f2f2">
<div style="padding: 10px" class="layui-col-xs4 layui-col-sm2 layui-col-md2 layui-col-lg2">
<img style=" width:auto; height:auto; max-width:100%; max-height:100%;" th:src="${book.picUrl}"/>
</div>
<div style="position:relative;padding: 10px 20px" class="layui-col-xs8 layui-col-sm8 layui-col-md8 layui-col-lg8">
<a th:href="'javascript:searchBooks(\''+ ${book.authorName}+'\')'"><div style=";color: #4c6978;" th:utext="'作者'+ ${book.authorName}"></div></a>
<a th:href="'/book/book_ranking.html?catId='+${book.catId}"><div style="margin-top: 5px;color: #4c6978;" th:text="'类别'+ ${book.catName}"></div></a>
<div style="margin-top: 5px;color: #4c6978;" th:text="'状态'+ ${book.bookStatus==0?'连载':'完结'}"></div>
<div style="margin-top: 5px;color: #4c6978;">更新:<i th:text="${#dates.format(book.lastIndexUpdateTime, 'yy-MM-dd')}"></i></div>
<div style="margin-top: 5px;color: #4c6978;">评分:<i style="font-weight:bold;color: red" th:text="${book.score} + '分'"></i></div>
<div style="margin-top: 5px;color: #4c6978;">点击:<i style="font-weight:bold;color: red" th:text="${book.visitCount}"></i></div>
</div>
</div>
<div style="text-align: center;height: 45px;line-height: 45px">
<a th:href="'/book/'+${book.id}+'/'+${firstBookIndexId}+'.html'" type="button" class="layui-btn layui-btn-sm layui-btn-radius">开始阅读</a>
<!--
<button type="button" onclick="downloadFile()" class="layui-btn layui-btn-sm layui-btn-radius layui-bg-normal">下载TXT</button>
-->
</div>
<p style="line-height: 23px;padding: 10px;font-size: 14px;color: #4c6978;" th:utext="${book.bookDesc}">
</p>
<div class="layui-collapse">
<div class="layui-colla-item" >
<h2 class="layui-colla-title">
<span>最新章节</span>
<span style="margin-left: 30px">
更新: <i th:text="${#dates.format(book.lastIndexUpdateTime, 'yy-MM-dd HH:mm:ss')}"></i>
</span>
</h2>
<div class="layui-colla-content layui-show indexP layui-row" id="indexList">
</div>
</div>
</div>
<div style="height: 42px;color:#4c6978;line-height: 42px;padding-left: 30px;background: #f2f2f2" >
<a th:href="'/book/indexList-'+${book.id}+'.html'">查看完整目录</a>
</div>
<!--
<div style="position: fixed;top:0px;left:0px;z-index:-100;opacity: 0" th:utext="${attacDivForSearch}"></div>
-->
</div>
<div th:replace="mobile/common/footer :: footer">
</div>
</body>
<div th:replace="mobile/common/js :: js">
</div>
<script>
//查询是否在书架
$.ajax({
type: "GET",
url: "/user/queryIsInShelf",
data: {'bookId': $("#bookIdHidden").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
if (data.data) {
$("#cFavs").html("<button type=\"button\" id=\"cFavs\" class=\"layui-btn layui-btn-sm layui-btn-radius layui-btn-warm\">已在书架</button>");
}
} else if (data.code == 1001) {
//未登录
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
//查询最新目录集合
$.ajax({
type: "GET",
url: "/book/queryNewIndexList",
data: {'bookId': $("#bookIdHidden").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
var indexListHtml = "";
for(var i = 0 ; i < data.data.length ; i++){
var bookIndex = data.data[i];
indexListHtml+=("<p class=\"line-limit-length layui-col-xs12 layui-col-sm4 layui-col-md3 layui-col-lg2\" style=\"padding-left:10px;height: 50px;line-height: 50px;\"><a href=\"/book/"+$("#bookIdHidden").val()+"/"+bookIndex.id+".html\">"+bookIndex.indexName+"</a></p>");
}
$("#indexList").html(indexListHtml);
} else if (data.code == 1001) {
//未登录
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
function addInShell() {
$.ajax({
type: "POST",
url: "/user/addToBookShelf",
data: {'bookId': $("#bookIdHidden").val(), 'preContentId': $("#preContentId").val()},
dataType: "json",
success: function (data) {
if (data.code == 200) {
$("#cFavs").html("<button type=\"button\" id=\"cFavs\" class=\"layui-btn layui-btn-sm layui-btn-radius layui-btn-warm\">已在书架</button>");
} else if (data.code == 1001) {
//未登录
location.href = '/user/login.html?originUrl=' + decodeURIComponent(location.href);
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
}
$("#content").css("min-height",($(window).height()-60)+"px");
function downloadFile() {
var fileUrl = '/book/download?bookId='+$("#bookIdHidden").val()+'&bookName='+$("#bookNamedHidden").val();
window.location.href=fileUrl;
}
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
function addToCollect(){
var token = localStorage.getItem("token");
if(token) {
$.get("/user/addToCollect",{"bookId":$("#bookIdHidden").val(),"token":token},function(data){
layer.alert(data.desc);
if(data.code == 1) {
$('#collectButton').unbind("click");
$("#collectButton").text("撤下书架");
$("#collectButton").click(function () {
cancelToCollect();
});
}
});
}else{
window.location.href = "/user/login.html?bookId="+$("#bookIdHidden").val();
}
}
function cancelToCollect(){
var token = localStorage.getItem("token");
if(token) {
$.get("/user/cancelToCollect",{"bookId":$("#bookIdHidden").val(),"token":token},function(data){
layer.alert(data.desc);
if(data.code == 1) {
$('#collectButton').unbind("click");
$("#collectButton").text("加入书架");
$("#collectButton").click(function () {
addToCollect();
});
}
});
}else{
window.location.href = "/user/login.html?bookId="+$("#bookIdHidden").val();
}
}
function searchBooks(keyword) {
window.location.href = "/book/book_ranking.html?keyword=" + encodeURI(keyword);
}
$.post("/book/addVisitCount", {"bookId": $("#bookIdHidden").val()}, function () {
});
</script>
</html>

View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:utext="${book.bookName}+'最新免费章节目录列表'"></title>
<meta name="keywords" th:content="${book.bookName}+','+${book.bookName}+'最新章节'">
<meta name="description"
th:content="${book.bookName}+'最新章节列表,'+${book.bookName}+'最新更新章节免费无广告无弹窗在线阅读TXT下载。'">
</div>
<div th:include="mobile/common/css :: css"></div>
<style type="text/css">
.indexP p a {
color: #4c6978;
}
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
</div>
</head>
<body>
<div id="content">
<input type="hidden" id="bookIdHidden" th:value="${book.id}"/>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<a style="color: #ffffff;" th:href="'/book/'+ ${book.id} + '.html'"><b class="layui-icon" th:utext="${book.bookName}"></b></a>
<div style="float: right;margin-right: 10px">
<a href="/"><i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i></a>
</div>
</div>
<p style="height: 30px;line-height: 30px;padding: 10px">
<a href="#buttom" style="color: red">&nbsp;&nbsp;↓直达页面底部</a>
</p>
<div class="layui-colla-content layui-show indexP layui-row">
<p class="line-limit-length layui-col-xs12 layui-col-sm4 layui-col-md3 layui-col-lg2" style="padding-left:10px;height: 50px;line-height: 50px;" th:each="index : ${bookIndexList}">
<a th:href="'/book/'+${index.bookId}+'/'+${index.id}+'.html'" th:utext="${index.indexName}">
</a>
</p>
</div>
</div>
<div th:replace="mobile/common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="mobile/common/js :: js">
</div>
<script>
$("#content").css("min-height",($(window).height()-60)+"px");
$.get("/book/addVisit",{"bookId":$("#bookIdHidden").val()},function(){});
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,320 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:text="#{website.name}+'列表'"></title>
<meta name="keywords"
th:content="#{website.name}+',精品小说,弹幕网站,弹幕,弹幕小说网站,免费小说,小说阅读,小说排行,轻小说,txt小说下载,电子书下载,动漫轻小说,日本轻小说'">
<meta name="description"
th:content="#{website.name}+'是国内优秀的小说弹幕网站,'+#{website.name}+'提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读和TXT小说下载,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜,致力于无广告无弹窗的小说阅读环境。'">
<div th:include="mobile/common/css :: css"></div>
</div>
<style type="text/css">
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indexP p a {
color: #4c6978;
}
.Readarea {
font-size: 18px;
line-height: 35px;
padding: 10px;
color: #333;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
.indexDiv a {
margin-left: 20px;
}
img {
width: 130px;
height: 180px;
}
</style>
</head>
<body>
<input type="hidden" id="limit" th:value="${limit}"/>
<input type="hidden" id="curr" th:value="${curr}"/>
<input type="hidden" id="total" th:value="${total}"/>
<input type="hidden" id="ids" th:value="${ids}"/>
<input type="hidden" id="bookStatus" th:value="${bookStatus}"/>
<input type="hidden" id="token" th:value="${token}"/>
<input type="hidden" id="keyword" th:value="${keyword}"/>
<input type="hidden" id="catId" th:value="${catId}"/>
<input type="hidden" id="sortBy" th:value="${sortBy}"/>
<input type="hidden" id="sort" th:value="${sort}"/>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon">小说列表</b>
<div style="float: right;margin-right: 10px">
<a href="/"><i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i></a>
</div>
</div>
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs10 layui-col-sm10 layui-col-md11 layui-col-lg11" style="padding-top:1%">
<input id="title" type="text" name="title" required lay-verify="required" placeholder="请输入书名·作者"
autocomplete="off"
class="layui-input" th:value="${keyword}">
</div>
<div class="layui-col-xs1" style="padding: 1%">
<button onclick="search(1,20)" class="layui-btn" lay-submit lay-filter="formDemo">搜索</button>
</div>
</div>
</div>
<div id="bookList">
</div>
<div id="books" style="text-align: center"></div>
<div th:replace="mobile/common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="mobile/common/js :: js"></div>
<script>
var catId = getQueryVariable("catId");
var bookStatus = getQueryVariable("bookStatus");
var sortBy = getQueryVariable("sortBy");
var keyword = getQueryVariable("keyword");
if(keyword != false){
$("#title").val(decodeURI(keyword));
}else{
keyword = "";
}
search(1,20);
function search(curr,limit) {
var searchData = {};
searchData.curr = curr;
searchData.limit = limit;
keyword = $("#title").val();
if(catId != false){
searchData.catId = catId;
}
if(bookStatus != false){
searchData.bookStatus = bookStatus;
}
if(sortBy != false){
searchData.sort = sortBy;
}else if(!keyword){
sortBy = "last_index_update_time";
}
if(keyword){
searchData.keyword = keyword;
}
$.ajax({
type: "GET",
url: "/book/searchByPage",
data: searchData,
dataType: "json",
success: function (data) {
if (data.code == 200) {
var bookList = data.data.list;
var bookListHtml = "";
for (var i = 0; i < bookList.length; i++) {
var book = bookList[i];
/*var end = book.bookDesc.indexOf("<");
if(end != -1) {
book.bookDesc = book.bookDesc.substring(0,end);
}*/
if(book.bookDesc){
book.bookDesc = book.bookDesc.replace(/<[^>]+>/g,"").replace(/\s+/g,"").replace(/&nbsp;/g,"");
}
bookListHtml += ("<div class=\"layui-row\" style=\"margin-bottom:10px;padding:10px;background: #f2f2f2\">\n" +
" <a href=\"/book/"+book.id+".html\">\n" +
" <div class=\"layui-col-xs6 layui-col-sm3 layui-col-md2 layui-col-lg2\" style=\"text-align: center\">\n" +
" <img width='150' height='180' align=\"center\"\n" +
" src=\""+book.picUrl+"\"/>\n" +
"\n" +
" </div>\n" +
" </a>\n" +
" <div style=\"padding: 10px\" class=\"layui-col-xs6 layui-col-sm8 layui-col-md8 layui-col-lg8\">\n" +
" <a href=\"/book/"+book.id+".html\">\n" +
" <div class=\"line-limit-length\" style=\";color: #4c6978;font-weight: bold;font-size: 15px\">"+book.bookName+"</div>\n" +
" </a>\n" +
" <div style=\";color: #4c6978;float: right;\"><i style=\"color: red\"></i></div>\n" +
" <a href=\"/book/book_ranking.html?keyword="+encodeURI(book.authorName)+"\">\n" +
" <div style=\";color: #4c6978;\" class=\"line-limit-length\">作者:"+book.authorName+"</div>\n" +
" </a>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">类别:"+book.catName+"</div>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">状态:"+(book.bookStatus==0?'连载':'完结')+"</div>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">更新:<i>"+book.lastIndexUpdateTime.substr(0,11)+"</i>\n" +
" </div>\n" +
" <div style=\"margin-top: 5px;color: #4c6978;\">简介:"+(book.bookDesc?(book.bookDesc.length>20?(book.bookDesc.substr(0,20)+"..."):book.bookDesc):book.bookDesc)+"</div>\n" +
"\n" +
"\n" +
" </div>\n" +
"\n" +
" </div>");
}
$("#bookList").html(bookListHtml);
layui.use('laypage', function () {
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
elem: 'books' //注意,这里的 test1 是 ID不用加 # 号
, count: data.data.total //数据总数,从服务端得到,
, curr: data.data.pageNum
, limit: data.data.pageSize
, jump: function (obj, first) {
//obj包含了当前分页的所有参数比如
console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。
console.log(obj.limit); //得到每页显示的条数
//首次不执行
if (!first) {
search(obj.curr, obj.limit);
} else {
}
}
});
});
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
}
function searchByAllCondition(curr, limit, newKeyword) {
var toUrl = "/book/search?curr=" + curr + "&limit=" + limit;
var ids = $("#ids").val();
if (ids) {
toUrl += ("&historyBookIds=" + ids);
}
var token = $("#token").val();
if (token) {
toUrl += ("&token=" + token);
}
var keyword = $("#keyword").val();
if (newKeyword) {
toUrl += encodeURI("&keyword=" + newKeyword);
} else if (keyword) {
toUrl += encodeURI("&keyword=" + keyword);
}
var bookStatus = $("#bookStatus").val();
if (bookStatus) {
toUrl += ("&bookStatus=" + bookStatus);
}
var catId = $("#catId").val();
if (catId) {
toUrl += ("&catId=" + catId);
}
var sortBy = $("#sortBy").val();
if (sortBy) {
toUrl += ("&sortBy=" + sortBy);
}
var sort = $("#sort").val();
if (sort) {
toUrl += ("&sort=" + sort);
}
window.location.href = toUrl;
}
function searchBooks() {
var keywords = $("#title").val();
$("#keyword").val("");
searchByAllCondition(1, 20, keywords);
}
</script>
<script>
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/search?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>小说提交</title>
<div th:include="common/css :: css"></div>
</head>
<body id="read" >
</div>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon">单本小说提交</b>
<div style="float: right;margin-right: 10px"><a href="/">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i>
</a>
</div>
</div>
<div style="height: 800px;padding: 20px;border: 1px solid #eee;">
<form class="layui-form" action="">
<div class="layui-form-item">
<label class="layui-form-label">详情页Url:</label>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md3 layui-col-lg1" >
<input type="text" id="bookUrl" name="bookUrl" required lay-verify="required" placeholder="请输入源站小说详情页Url" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">小说名:</label>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md3 layui-col-lg1" >
<input type="text" id="bookName" name="bookName" required lay-verify="required" placeholder="请输入小说名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">小说评分:</label>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md3 layui-col-lg1">
<input type="number" id="score" name="score" required lay-verify="required" placeholder="请输入小说评分" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
<div th:replace="common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="common/js :: js"></div>
<script>
//Demo
layui.use('form', function(){
var form = layui.form;
//监听提交
form.on('submit(formDemo)', function(){
$.post("/book/submit",{"bookUrl":$("#bookUrl").val(),"bookName":$("#bookName").val(),"score":$("#score").val()},function (data) {
if(data.code == 1 ){
layer.alert("提交成功任务排队中请过一段时间后再搜索查看");
}else{
layer.alert("提交失败");
}
});
return false;
});
});
</script>
</html>

View File

@ -0,0 +1,270 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:text="${application.seoConfig.page['mh-search.title']}"></title>
<meta name="keywords" th:content="${application.seoConfig.page['mh-search.keyword']}">
<meta name="description"
th:content="${application.seoConfig.page['mh-search.description']}">
<div th:include="common/css :: css"></div>
</div>
<style type="text/css">
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indexP p a {
color: #4c6978;
}
.Readarea {
font-size: 18px;
line-height: 35px;
padding: 10px;
color: #333;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
.indexDiv a {
margin-left: 20px;
}
img {
width: 147px;
height: 197px;
}
</style>
</head>
<body>
<input type="hidden" id="limit" th:value="${limit}"/>
<input type="hidden" id="curr" th:value="${curr}"/>
<input type="hidden" id="total" th:value="${total}"/>
<input type="hidden" id="ids" th:value="${ids}"/>
<input type="hidden" id="keyword" th:value="${keyword}"/>
<input type="hidden" id="softTag" th:value="${softTag}"/>
<input type="hidden" id="sortBy" th:value="${sortBy}"/>
<input type="hidden" id="sort" th:value="${sort}"/>
<input type="hidden" id="bookStatus" th:value="${bookStatus}"/>
<input type="hidden" id="softCat" th:value="${softCat}"/>
<ul class="layui-nav" lay-filter="" style="padding:0 20px;text-align: center" >
<li id="menunew" class="layui-nav-item"><a href="/book/searchSoftBook.html?catId=9">最新</a></li>
<li id="menu21" class="layui-nav-item"><a href="/book/searchSoftBook.html?catId=9&softCat=3262">少年漫</a></li>
<li id="menu22" class="layui-nav-item"><a href="/book/searchSoftBook.html?catId=9&softCat=3263">少女漫</a></li>
<li id="menucomplete" class="layui-nav-item"><a >完本</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/searchSoftBook.html?catId=9&bookStatus=已完成">全部</a></dd>
<dd><a href="/book/searchSoftBook.html?catId=9&bookStatus=已完成&softCat=3262">少年漫</a></dd>
<dd><a href="/book/searchSoftBook.html?catId=9&bookStatus=已完成&softCat=3263">少女漫</a></dd>
</dl>
</li>
<li id="menuhot" class="layui-nav-item"><a >排行</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/searchSoftBook.html?catId=9&sortBy=score">全部</a></dd>
<dd><a href="/book/searchSoftBook.html?catId=9&sortBy=score&softCat=3262">少年漫</a></dd>
<dd><a href="/book/searchSoftBook.html?catId=9&bookStatus=已完成&softCat=3263">少女漫</a></dd>
</dl>
</li>
</ul>
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs10 layui-col-sm10 layui-col-md11 layui-col-lg11" style="padding-top:1%">
<input id="title" type="text" name="title" required lay-verify="required" placeholder="请输入书名·作者"
autocomplete="off"
class="layui-input" th:value="${keyword}">
</div>
<div class="layui-col-xs1" style="padding: 1%">
<button onclick="searchBooks()" class="layui-btn" lay-submit lay-filter="formDemo">搜索</button>
</div>
</div>
</div>
<div th:each="book : ${books}" class="layui-row" style="margin-bottom:10px;padding:10px;background: #f2f2f2">
<a th:href="'/book/'+ ${book.id} + '.html'">
<div class="layui-col-xs6 layui-col-sm3 layui-col-md2 layui-col-lg2" style="text-align: center" th:switch = "${application.noLazy}">
<img th:case="'1'" align="center"
th:attr="data-src=${book.picUrl}"/>
<img th:case="*" align="center"
class="lazyload" th:attr="data-src=${book.picUrl}"/>
</div>
</a>
<div style="padding: 20px" class="layui-col-xs6 layui-col-sm8 layui-col-md8 layui-col-lg8">
<a th:href="'/book/'+ ${book.id} + '.html'">
<div class="line-limit-length" style=";color: #4c6978;font-weight: bold;font-size: 15px"
th:text="${book.bookName}"></div>
</a>
<div style=";color: #4c6978;float: right;"><i style="color: red" th:text="${book.score} + '分'"></i></div>
<a th:href="'/book/searchSoftBook.html?catId=9&keyword='+ ${book.author}">
<div style=";color: #4c6978;" class="line-limit-length" th:text="'作者'+ ${book.author}"></div>
</a>
<div style="margin-top: 5px;color: #4c6978;" th:text="'类别'+ ${book.cateName}"></div>
<div style="margin-top: 5px;color: #4c6978;" th:text="'状态'+ ${book.bookStatus}"></div>
<div style="margin-top: 5px;color: #4c6978;">更新:<i th:text="${#dates.format(book.updateTime, 'yy-MM-dd')}"></i>
</div>
<div class="layui-collapse" style="margin-top: 5px;">
<div class="layui-colla-item">
<h2 style="color: #4c6978;" class="layui-colla-title">简介:</h2>
<div style="color: #4c6978;" class="layui-colla-content" th:utext="${book.bookDesc}">
</div>
</div>
</div>
</div>
</div>
<div id="books" style="text-align: center"></div>
<div th:replace="common/soft_footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="common/js :: js"></div>
<script src="/js/lazyload.js"></script>
<script>
lazyload();
layui.use('laypage', function () {
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
elem: 'books' //注意,这里的 test1 是 ID不用加 # 号
, count: $("#total").val() //数据总数,从服务端得到,
, curr: $("#curr").val()
, limit: $("#limit").val()
, jump: function (obj, first) {
//obj包含了当前分页的所有参数比如
console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。
console.log(obj.limit); //得到每页显示的条数
//首次不执行
if (!first) {
searchByAllCondition(obj.curr,obj.limit);
} else {
}
}
});
});
function searchByAllCondition(curr,limit,newKeyword){
var toUrl = "/book/searchSoftBook.html?catId=9&curr=" + curr + "&limit=" + limit;
var ids = $("#ids").val();
if(ids){
toUrl += ("&historyBookIds=" + ids);
}
var keyword = $("#keyword").val();
if(newKeyword){
toUrl += encodeURI("&keyword=" + newKeyword);
}else if (keyword) {
toUrl += encodeURI("&keyword=" + keyword);
}
var bookStatus = $("#bookStatus").val();
if(bookStatus){
toUrl += ("&bookStatus=" + bookStatus);
}
var softCat = $("#softCat").val();
if (softCat) {
toUrl += ("&softCat=" + softCat);
}
var softTag = $("#softTag").val();
if (softTag) {
toUrl += ("&softTag=" + softTag);
}
var sortBy = $("#sortBy").val();
if (sortBy) {
toUrl += ("&sortBy=" + sortBy);
}
var sort = $("#sort").val();
if (sort) {
toUrl += ("&sort=" + sort);
}
window.location.href = toUrl;
}
function searchBooks() {
var keywords = $("#title").val();
$("#keyword").val("");
searchByAllCondition(1,20,keywords);
}
</script>
<script>
(function(){
var sortCat = $("#softCat").val();
var sortBy = $("#sortBy").val();
if(sortBy == 'score'){
$("#menuhot").addClass("layui-this");
}else if($("#bookStatus").val()){
$("#menucomplete").addClass("layui-this");
}else if(sortCat){
$("#menu"+sortCat).addClass("layui-this");
}else{
$("#menunew").addClass("layui-this");
}
})();
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,294 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:text="${application.seoConfig.page['soft-search.title']}"></title>
<meta name="keywords" th:content="${application.seoConfig.page['soft-search.keyword']}">
<meta name="description"
th:content="${application.seoConfig.page['soft-search.description']}">
<div th:include="common/css :: css"></div>
</div>
<style type="text/css">
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.indexP p a {
color: #4c6978;
}
.Readarea {
font-size: 18px;
line-height: 35px;
padding: 10px;
color: #333;
}
div, p {
wrap-work: break-word;
word-break: break-all;
word-wrap: break-word;
word-break: normal;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-ms-box-sizing: border-box;
}
.indexDiv a {
margin-left: 20px;
}
img {
width: 147px;
height: 197px;
}
</style>
</head>
<body>
<input type="hidden" id="limit" th:value="${limit}"/>
<input type="hidden" id="curr" th:value="${curr}"/>
<input type="hidden" id="total" th:value="${total}"/>
<input type="hidden" id="ids" th:value="${ids}"/>
<input type="hidden" id="keyword" th:value="${keyword}"/>
<input type="hidden" id="softTag" th:value="${softTag}"/>
<input type="hidden" id="sortBy" th:value="${sortBy}"/>
<input type="hidden" id="sort" th:value="${sort}"/>
<input type="hidden" id="bookStatus" th:value="${bookStatus}"/>
<input type="hidden" id="softCat" th:value="${softCat}"/>
<ul class="layui-nav" lay-filter="" style="padding:0 20px;text-align: center">
<li id="menunew" class="layui-nav-item"><a href="/book/searchSoftBook.html">最新</a></li>
<li id="menu21" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=21">魔幻</a></li>
<li id="menu22" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=22">玄幻</a></li>
<li id="menu23" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=23">古风</a></li>
<li id="menu24" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=24">科幻</a></li>
<li id="menu25" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=25">校园</a></li>
<li id="menu26" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=26">都市</a></li>
<li id="menu27" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=27">游戏</a></li>
<li id="menu28" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=28">同人</a></li>
<li id="menu29" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=29">悬疑</a></li>
<li id="menu0" class="layui-nav-item"><a href="/book/searchSoftBook.html?softCat=0">动漫</a></li>
<li id="menucomplete" class="layui-nav-item"><a>完本</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成">全部</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=21">魔幻</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=22">玄幻</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=23">古风</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=24">科幻</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=25">校园</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=26">都市</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=27">游戏</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=28">同人</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=29">悬疑</a></dd>
<dd><a href="/book/searchSoftBook.html?bookStatus=已完成&softCat=0">动漫</a></dd>
</dl>
</li>
<li id="menuhot" class="layui-nav-item"><a>排行</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/searchSoftBook.html?sortBy=score">全部</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=21">魔幻</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=22">玄幻</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=23">古风</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=24">科幻</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=25">校园</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=26">都市</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=27">游戏</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=28">同人</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=29">悬疑</a></dd>
<dd><a href="/book/searchSoftBook.html?sortBy=score&softCat=0">动漫</a></dd>
</dl>
</li>
</ul>
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs10 layui-col-sm10 layui-col-md11 layui-col-lg11" style="padding-top:1%">
<input id="title" type="text" name="title" required lay-verify="required" placeholder="请输入书名·作者"
autocomplete="off"
class="layui-input" th:value="${keyword}">
</div>
<div class="layui-col-xs1" style="padding: 1%">
<button onclick="searchBooks()" class="layui-btn" lay-submit lay-filter="formDemo">搜索</button>
</div>
</div>
</div>
<div th:each="book : ${books}" class="layui-row" style="margin-bottom:10px;padding:10px;background: #f2f2f2">
<a th:href="'/book/'+ ${book.id} + '.html'">
<div class="layui-col-xs6 layui-col-sm3 layui-col-md2 layui-col-lg2" style="text-align: center"
th:switch="${application.noLazy}">
<img th:case="'1'" align="center"
th:attr="data-src=${book.picUrl}"/>
<img th:case="*" align="center"
class="lazyload" th:attr="data-src=${book.picUrl}"/>
</div>
</a>
<div style="padding: 20px" class="layui-col-xs6 layui-col-sm8 layui-col-md8 layui-col-lg8">
<a th:href="'/book/'+ ${book.id} + '.html'">
<div class="line-limit-length" style=";color: #4c6978;font-weight: bold;font-size: 15px"
th:text="${book.bookName}"></div>
</a>
<div style=";color: #4c6978;float: right;"><i style="color: red" th:text="${book.score} + '分'"></i></div>
<a th:href="'/book/searchSoftBook.html?keyword='+ ${book.author}">
<div style=";color: #4c6978;" class="line-limit-length" th:text="'作者'+ ${book.author}"></div>
</a>
<div style="margin-top: 5px;color: #4c6978;" th:text="'类别'+ ${book.cateName}"></div>
<div style="margin-top: 5px;color: #4c6978;" th:text="'状态'+ ${book.bookStatus}"></div>
<div style="margin-top: 5px;color: #4c6978;">更新:<i th:text="${#dates.format(book.updateTime, 'yy-MM-dd')}"></i>
</div>
<div class="layui-collapse" style="margin-top: 5px;">
<div class="layui-colla-item">
<h2 style="color: #4c6978;" class="layui-colla-title">简介:</h2>
<div style="color: #4c6978;" class="layui-colla-content" th:utext="${book.bookDesc}">
</div>
</div>
</div>
</div>
</div>
<div id="books" style="text-align: center"></div>
<div th:replace="common/soft_footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="common/js :: js"></div>
<script src="/js/lazyload.js"></script>
<script>
lazyload();
layui.use('laypage', function () {
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
elem: 'books' //注意,这里的 test1 是 ID不用加 # 号
, count: $("#total").val() //数据总数,从服务端得到,
, curr: $("#curr").val()
, limit: $("#limit").val()
, jump: function (obj, first) {
//obj包含了当前分页的所有参数比如
console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。
console.log(obj.limit); //得到每页显示的条数
//首次不执行
if (!first) {
searchByAllCondition(obj.curr, obj.limit);
} else {
}
}
});
});
function searchByAllCondition(curr, limit, newKeyword) {
var toUrl = "/book/searchSoftBook.html?curr=" + curr + "&limit=" + limit;
var ids = $("#ids").val();
if (ids) {
toUrl += ("&historyBookIds=" + ids);
}
var keyword = $("#keyword").val();
if (newKeyword) {
toUrl += encodeURI("&keyword=" + newKeyword);
} else if (keyword) {
toUrl += encodeURI("&keyword=" + keyword);
}
var bookStatus = $("#bookStatus").val();
if (bookStatus) {
toUrl += ("&bookStatus=" + bookStatus);
}
var softCat = $("#softCat").val();
if (softCat) {
toUrl += ("&softCat=" + softCat);
}
var softTag = $("#softTag").val();
if (softTag) {
toUrl += ("&softTag=" + softTag);
}
var sortBy = $("#sortBy").val();
if (sortBy) {
toUrl += ("&sortBy=" + sortBy);
}
var sort = $("#sort").val();
if (sort) {
toUrl += ("&sort=" + sort);
}
window.location.href = toUrl;
}
function searchBooks() {
var keywords = $("#title").val();
$("#keyword").val("");
searchByAllCondition(1, 20, keywords);
}
</script>
<script>
(function () {
var sortCat = $("#softCat").val();
var sortBy = $("#sortBy").val();
if (sortBy == 'score') {
$("#menuhot").addClass("layui-this");
} else if ($("#bookStatus").val()) {
$("#menucomplete").addClass("layui-this");
} else if (sortCat) {
$("#menu" + sortCat).addClass("layui-this");
} else {
$("#menunew").addClass("layui-this");
}
})();
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/search?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,24 @@
<div th:fragment="css">
<link rel="stylesheet" href="/mobile/layui/css/layui.css">
<style type="text/css">
.app {
display: none;
}
@media (max-width: 360px) {
.app {
display: block !important;
}
}
.pc {
display: block;
}
@media (max-width: 360px) {
.pc {
display: none;
}
}
</style>
</div>

View File

@ -0,0 +1,11 @@
<div th:fragment="footer" style="height: 60px;line-height: 60px;text-align: center" class="layui-footer footer footer-demo layui-bg-cyan">
<!--<a href="/mobile/book/searchSoftBook.html" style="font-size: 14px;color: #92B8B1;">轻小说</a>
<a href="/mobile/book/searchSoftBook.html?catId=9" style="font-size: 14px;color: #92B8B1;margin-left: 8px">漫画</a>-->
<a href="/?to=pc" style="font-size: 14px;color: #92B8B1;margin-left: 8px">电脑站</a>
<!--<a href="https://www.zinglizingli.xyz/me/index.html" style="font-size: 14px;color: #92B8B1;margin-left: 8px">开发者</a>-->
<div style="float: right"><a href="#top"><i class="layui-icon"
style="margin-right:15px;font-size: 30px;color:#92B8B1 ">&#xe604;</i></a>
</div>
</div>

View File

@ -0,0 +1,3 @@
<script th:fragment="js" src="/mobile/js/jquery-1.9.1.js"></script>
<script th:fragment="js" src="/mobile/js/common.js"></script>
<script th:fragment="js" src="/mobile/layui/layui.all.js"></script>

View File

@ -0,0 +1,19 @@
<div th:fragment="footer" style="height: 60px;line-height: 60px;text-align: center" class="layui-footer footer footer-demo layui-bg-cyan">
<a href="/book" style="font-size: 14px;color: #92B8B1;">更多小说</a>
<a href="javascript:readHistory()" style="font-size: 14px;color: #92B8B1;margin-left: 8px">阅读记录</a>
<a href="javascript:toMyCollect()" style="font-size: 14px;color: #92B8B1;margin-left: 8px">书架</a>
<a href="/mobile/HotBook.apk" style="font-size: 14px;color: #92B8B1;margin-left: 8px">客户端</a>
<!--<a href="https://www.zinglizingli.xyz/me/index.html" style="font-size: 14px;color: #92B8B1;margin-left: 8px">开发者</a>-->
<div style="float: right"><a href="#top"><i class="layui-icon"
style="margin-right:15px;font-size: 30px;color:#92B8B1 ">&#xe604;</i></a>
</div>
<script>
(function(){
var src = (document.location.protocol == "http:") ? "http://js.passport.qihucdn.com/11.0.1.js?0acfeb0f37ba0d8942c2bbf459016f21":"https://jspassport.ssl.qhimg.com/11.0.1.js?0acfeb0f37ba0d8942c2bbf459016f21";
document.write('<script src="' + src + '" id="sozz"><\/script>');
})();
</script>
</div>

View File

@ -0,0 +1,388 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title th:text="#{website.name}"></title>
<meta name="keywords" th:content="#{website.name}+',精品小说,弹幕网站,弹幕,弹幕小说网站,免费小说,小说阅读,小说排行,轻小说,txt小说下载,电子书下载,动漫轻小说,日本轻小说'">
<meta name="description"
th:content="#{website.name}+'是国内优秀的小说弹幕网站,'+#{website.name}+'提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读和TXT小说下载,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜,致力于无广告无弹窗的小说阅读环境。'">
<meta property="og:type" content="novel_index"/>
<meta property="og:title" th:content="#{website.name}"/>
<meta property="og:description"
th:content="#{website.name}+'是国内优秀的小说弹幕网站,'+#{website.name}+'提供海量热门网络小说,日本轻小说,国产轻小说,动漫小说,轻小说在线阅读和TXT小说下载,致力于网络精品小说的收集,智能计算小说评分,打造小说精品排行榜,致力于无广告无弹窗的小说阅读环境。'"/>
<div th:include="mobile/common/css :: css"></div>
<style>
.line-limit-length {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.layui-nav .layui-nav-item {
position: relative;
display: inline-block;
vertical-align: middle;
line-height: 50px;
}
body ul.layui-nav li.layui-nav-item a {
display: block;
transition: all .3s;
-webkit-transition: all .3s;
}
</style>
</head>
<body>
<!-- 你的HTML代码 -->
<a name="top"></a>
<ul class="layui-nav app" lay-filter="" style="display:none;padding:0 10px;text-align: center">
<li class="layui-nav-item"><a>分类</a>
<dl class="layui-nav-child">
<dd><a href="/book/book_ranking.html?catId=1&sort=last_index_update_time">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=2&sort=last_index_update_time">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=3&sort=last_index_update_time">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=4&sort=last_index_update_time">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=6&sort=last_index_update_time">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=5&sort=last_index_update_time">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?catId=7&sort=last_index_update_time">女频小说</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a>全本</a>
<dl class="layui-nav-child">
<dd><a href="/book/book_ranking.html?bookStatus=1">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=7">女频小说</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a>排行</a>
<dl class="layui-nav-child">
<dd><a href="/book/book_ranking.html?sortBy=visit_count">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=7">女频小说</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav pc" lay-filter="" style="padding:0 36px;text-align: center">
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=1&sort=last_index_update_time">玄幻小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=2&sort=last_index_update_time">修真小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=3&sort=last_index_update_time">都市小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=4&sort=last_index_update_time">历史小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=6&sort=last_index_update_time">网游小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=5&sort=last_index_update_time">科幻小说</a></li>
<li class="layui-nav-item"><a href="/book/book_ranking.html?catId=7&sort=last_index_update_time">女频小说</a></li>
<li class="layui-nav-item"><a>完本小说</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/book_ranking.html?bookStatus=1">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?bookStatus=1&catId=7">女频小说</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a>小说排行</a>
<dl class="layui-nav-child"> <!-- 二级菜单 -->
<dd><a href="/book/book_ranking.html?sortBy=visit_count">全部小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=1">玄幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=2">修真小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=3">都市小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=4">历史小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=6">网游小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=5">科幻小说</a></dd>
<dd><a href="/book/book_ranking.html?sortBy=visit_count&catId=7">女频小说</a></dd>
</dl>
</li>
</ul>
<div class="layui-container">
<div class="layui-row">
<div class="layui-col-xs10 layui-col-sm10 layui-col-md11 layui-col-lg11" style="padding-top:1%">
<input id="title" type="text" name="title" required lay-verify="required" placeholder="请输入书名·作者"
autocomplete="off"
class="layui-input">
</div>
<div class="layui-col-xs1" style="padding: 1%">
<button onclick="searchBooks()" class="layui-btn" lay-submit lay-filter="formDemo">搜索</button>
</div>
</div>
</div>
<div style="height: 1px" class="layui-col-lg1"></div>
<div class="layui-collapse layui-col-lg10">
<div class="layui-colla-item">
<h2 class="layui-colla-title">本站推荐</h2>
<div class="layui-colla-content layui-show">
<div class="layui-container" style="padding: 0px">
<div class="layui-row" style="text-align: center" id="currentWeek">
</div>
</div>
</div>
</div>
<div class="layui-colla-item">
<h2 class="layui-colla-title">热门小说推荐</h2>
<div class="layui-colla-content layui-show">
<div class="layui-container">
<div class="layui-row" id="hotRecBooks">
<!--<div th:each="hotBook : ${hotBooks}" style="margin-top: 1%"
class="layui-col-xs12 layui-col-sm6 layui-col-md6 layui-col-lg6">
<a th:href="'/book/'+${hotBook.id}+'.html'">
<div class="layui-col-xs5 layui-col-sm3 layui-col-md3 layui-col-lg3">
<img style=" width:100px; height:125px;"
th:src="${hotBook.picUrl}"/>
</div>
<div class="layui-col-xs7 layui-col-sm6 layui-col-md7 layui-col-lg7"
style="float: left;padding-right: 10px">
<div><b th:text="${hotBook.bookName}"></b></div>
<div class="layui-col-xs8 layui-col-sm9 layui-col-md10 layui-col-lg10"
th:text="'作者'+ ${hotBook.author}"></div>
<div class="layui-col-xs3 layui-col-sm2 layui-col-md1 layui-col-lg1" style="text-align: right;">
<b><i style="color: red"
th:text="${hotBook.score} + '分'"></i></b></div>
</div>
<div class="layui-elip layui-col-xs12 layui-col-sm9 layui-col-md10 layui-col-lg10 layui-col-sm9 layui-col-md10 layui-col-lg10"
th:text="${hotBook.bookDesc}">
</div>
</a>
</div>-->
</div>
</div>
</div>
</div>
</div>
</div>
<div style="clear: both"></div>
<div style="height: 1px" class="layui-col-lg1"></div>
<div class="layui-colla-item layui-col-lg10"
style="border-width: 1px;border-style: solid;border-radius: 2px;border-top-width: 0px"><a
href="javascript:moreNewBooks()">
<h2 class="layui-colla-title">最近更新小说
<div style="float: right; margin-right: 20px"><i style="font-size: 14px;"
class="layui-icon">更多&#xe65b;</i>
</div>
</h2>
</a>
<div class="layui-colla-content layui-show">
<div class="layui-container" style="padding-left: 2px;padding-right: 5px">
<div class="layui-row" id="updateRankBooks">
</div>
</div>
</div>
</div>
</div>
<div style="clear: both"></div>
<div th:replace="mobile/common/footer :: footer">
</div>
<div th:replace="mobile/common/js :: js">
</div>
<script src="/mobile/js/wap_collect.js"></script>
<script>
//加载首页书籍设置数据
$.ajax({
type: "GET",
url: "/book/listBookSetting",
data: {},
dataType: "json",
success: function (data) {
if (data.code == 200) {
//本周强推
var rightListBooks = data.data[2];
var rightListBooksHtml = "";
for (var i = 0; i < 3; i++) {
var rightListBook = rightListBooks[i];
var classHtml = "";
if (i == 0) {
classHtml = "on";
}
if (i < 3) {
classHtml += (" num" + (i + 1));
}
rightListBooksHtml += (" <span>\n" +
" <a href=\"/book/"+rightListBook.bookId+".html\">\n" +
" <div style=\"padding: 1%\" class=\"layui-col-xs4 layui-col-sm4 layui-col-md4 layui-col-lg4\">\n" +
" <img style=\" width:80%; height:auto; max-width:100%; max-height:100%;\"\n" +
" src=\""+rightListBook.picUrl+"\"/>\n" +
"\n" +
" <br/>\n" +
" <span>"+rightListBook.bookName+"</span>\n" +
"\n" +
" </div>\n" +
" </a>\n" +
" </span>");
}
$("#currentWeek").html(rightListBooksHtml);
//热门推荐
var hotRecBooks = data.data[3];
var hotRecBooksHtml = "";
for (var i = 0; i < 6; i++) {
var hotRecBook = hotRecBooks[i];
if(hotRecBook.bookDesc){
hotRecBook.bookDesc = hotRecBook.bookDesc.replace(/<[^>]+>/g,"").replace(/\s+/g,"");
}
hotRecBooksHtml += ("<div style=\"margin-bottom: 5px\" class=\"layui-col-xs12 layui-col-sm6 layui-col-md4 layui-col-lg4\">\n" +
" <a href=\"/book/"+hotRecBook.bookId+".html\">\n" +
" <div class=\"layui-col-xs5 layui-col-sm4 layui-col-md4 layui-col-lg4\" >\n" +
" <img style=\" width:100px; height:125px;\"\n" +
" src=\""+hotRecBook.picUrl+"\"/>\n" +
"\n" +
" </div>\n" +
" <div class=\"layui-col-xs5 layui-col-sm6 layui-col-md6 layui-col-lg6\">\n" +
" <ul>\n" +
" <li class=\"line-limit-length\" style=\"font-weight: bold\">"+hotRecBook.bookName+"</li>\n" +
" <li>作者:"+hotRecBook.authorName+"</li>\n" +
" <li style=\"width: 180px;height:40px;overflow: hidden\">简介:  "+hotRecBook.bookDesc+"" +
" </ul>\n" +
" </div>\n" +
" <div style=\"font-style: italic;color: red\"\n" +
" class=\"layui-col-xs2 layui-col-sm2 layui-col-md2 layui-col-lg2\"></div>\n" +
" </a>\n" +
" </div>");
}
$("#hotRecBooks").html(hotRecBooksHtml);
} else {
layer.alert(data.msg);
}
},
error: function () {
layer.alert('网络异常');
}
})
//更新榜单查询
$.ajax({
type: "GET",
url: "/book/listUpdateRank",
data: {},
dataType: "json",
success: function (data) {
if (data.code == 200) {
var updateRankBooks = data.data;
var updateRankBookHtml = "";
for (var i = 0; i < 10; i++) {
var updateRankBook = updateRankBooks[i];
if(updateRankBook.bookDesc){
updateRankBook.bookDesc = updateRankBook.bookDesc.replace(/<[^>]+>/g,"").replace(/\s+/g,"");
}
updateRankBookHtml += ("<div style=\"padding-bottom: 30px\"\n" +
" class=\"layui-col-xs12 layui-col-sm6 layui-col-md6 layui-col-lg6\">\n" +
"\n" +
" <a href=\"/book/"+updateRankBook.id+".html\">\n" +
" <div class=\"line-limit-length layui-col-xs8 layui-col-sm6 layui-col-md6 layui-col-lg6\"><b>"+(i+1)+"."+updateRankBook.bookName+"</b> - <span class=\"layui-elip\">"+updateRankBook.authorName+"</span>\n" +
" </div>\n" +
" <div class=\"layui-col-sm3 layui-col-md3 layui-col-lg3\"\n" +
" style=\"color: #FF5722;float: right;margin-right:5px\"><i>"+updateRankBook.lastIndexUpdateTime+"</i></div>\n" +
"\n" +
" <div style=\"clear: both\"></div>\n" +
" <div style=\"padding-left: 5px;padding-top: 5px\"\n" +
" class=\"layui-elip layui-col-md11 layui-col-sm11 layui-col-lg11\">简介:  "+updateRankBook.bookDesc+"" +
" </div></a>\n" +
" </div>");
}
$("#updateRankBooks").html(updateRankBookHtml);
} else {
layer.alert(data.msg);
}
}
,
error: function () {
layer.alert('网络异常');
}
})
function moreNewBooks(event) {
window.location.href = "/book/book_ranking.html?sortBy=last_index_update_time";
}
function searchBooks() {
var keywords = $("#title").val();
window.location.href = "/book/book_ranking.html?keyword=" + encodeURI(keywords);
}
function toMyCollect() {
var token = localStorage.getItem("token");
if (token) {
window.location.href = "/book/book_ranking.html?token=" + token;
} else {
window.location.href = "/user/login.html";
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>登录|注册</title>
<div th:include="common/css :: css"></div>
</head>
<body id="read" >
</div>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon">登录|注册</b>
<div style="float: right;margin-right: 10px"><a href="/">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i>
</a>
</div>
</div>
<form style="height: 500px;margin-top: 50px" class="layui-form" action="">
<input type="hidden" id="bookIdHidden" name="bookId" th:value="${bookId}"/>
<div class="layui-form-item">
<label class="layui-form-label">登录名</label>
<div class="layui-input-block">
<input type="text" id="loginName" name="loginName" required lay-verify="required" placeholder="请输入登录名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-inline">
<input id="password" type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">如果登录名不存在,则直接注册!</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">登录|注册</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<div th:replace="common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="common/js :: js"></div>
<script>
$.get("/book/addVisit",{"bookId":$("#bookIdHidden").val()},function(){});
</script>
<script>
//Demo
layui.use('form', function(){
var form = layui.form;
//监听提交
form.on('submit(formDemo)', function(){
$.post("/user/loginOrRegist",{"bookId":$("#bookIdHidden").val(),"loginName":$("#loginName").val(),"password":$("#password").val()},function (data) {
if(data.code == 1 || data.code == 2){
localStorage.setItem("token",data.token);
layer.alert(data.desc);
setTimeout(function () {
var bookId = $("#bookIdHidden").val();
if(bookId){
//加入书架
window.location.href="/book/"+bookId+".html";
}else{
//我的书架
window.location.href="/book/search?token="+data.token;
}
},3000)
}else{
layer.alert(data.desc);
}
});
return false;
});
});
</script>
<script>
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
</script>
</html>

View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>登录|注册</title>
<div th:include="common/css :: css"></div>
</head>
<body id="read" >
</div>
<div style="height: 50px;line-height: 50px;text-align: center" class="layui-header header header-doc layui-bg-cyan">
<div style="float: left;margin-left: 10px">
<a href="javascript:history.go(-1)">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe65c;</i></a>
</div>
<b class="layui-icon">登录|注册</b>
<div style="float: right;margin-right: 10px"><a href="/">
<i style="font-size: 20px;color: #92B8B1;" class="layui-icon">&#xe68e;</i>
</a>
</div>
</div>
<form style="height: 500px;margin-top: 50px" class="layui-form" action="">
<input type="hidden" id="bookIdHidden" name="bookId" th:value="${bookId}"/>
<div class="layui-form-item">
<label class="layui-form-label">登录名</label>
<div class="layui-input-block">
<input type="text" id="loginName" name="loginName" required lay-verify="required" placeholder="请输入登录名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-inline">
<input id="password" type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">如果登录名不存在,则直接注册!</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">登录|注册</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<div th:replace="common/footer :: footer">
</div>
<a name="buttom"></a>
</body>
<div th:replace="common/js :: js"></div>
<script>
$.get("/book/addVisit",{"bookId":$("#bookIdHidden").val()},function(){});
</script>
<script>
//Demo
layui.use('form', function(){
var form = layui.form;
//监听提交
form.on('submit(formDemo)', function(){
$.post("/user/loginOrRegist",{"bookId":$("#bookIdHidden").val(),"loginName":$("#loginName").val(),"password":$("#password").val()},function (data) {
if(data.code == 1 || data.code == 2){
localStorage.setItem("token",data.token);
layer.alert(data.desc);
setTimeout(function () {
var bookId = $("#bookIdHidden").val();
if(bookId){
//加入书架
window.location.href="/book/"+bookId+".html";
}else{
//我的书架
window.location.href="/book/search?token="+data.token;
}
},3000)
}else{
layer.alert(data.desc);
}
});
return false;
});
});
</script>
<script>
function toMyCollect(){
var token = localStorage.getItem("token");
if(token) {
window.location.href = "/book/search?token=" + token;
}else{
window.location.href = "/user/login.html";
}
}
</script>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -0,0 +1,270 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta name="generator" content="Aspose.Words for .NET 15.1.0.0"/>
<title>RestTemplate中文乱码问题源码分析与解决</title></head>
<body>
<div><p style="font-size:18pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_499-1566046872517"></a><a
style="color:#003884" href="http://www.zinglizingli.xyz"><span
style="background-color:#ffffff; color:#003884; font-family:'Times New Roman'; font-size:18pt; font-weight:bold; text-decoration:underline">RestTemplate中文乱码问题源码分析与解决</span></a>
</p>
<p style="font-size:18pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_668-1566076102707"></a><span
style="background-color:#ffffff; color:#393939; font-family:'Times New Roman'; font-size:18pt; font-weight:bold">---  请求响应数据乱码源码原理分析</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_359-1566070296357"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_090-1566070299368"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="margin:0pt"><a name="_374-1566070299635"></a><span
style="background-color:#ffffff; color:#df402a; font-family:微软雅黑; font-size:15pt; font-weight:bold">============================原理===================</span>
</p>
<p style="margin:0pt"><a name="_115-1566075419335"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">//默认方式:</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_398-1566075426884"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">//RestTemplate restTemplate = new RestTemplate();</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_535-1566075426884"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">// 当返回的response-header的content-type属性有charset值时</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_832-1566075426884"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">// restTemplate的 StringHttpMessageConverter会读取该charset值并使用该值进行</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_044-1566081046911"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">//IO流 = 》字符串的转换,否则则使用默认的字符集</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_025-1566075590776"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">// </span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_437-1566081514760"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_917-1566081515252"></a><span
style="color:#7b5ba1; font-family:SimSun; font-size:11pt; font-style:italic">通过源码可以发现restTemplate底层默认使用了</span><span
style="background-color:#ff0000; color:#ffffff; font-family:SimSun; font-size:11pt">HttpURLConnection</span><span
style="background-color:#ffffff; color:#7b5ba1; font-family:SimSun; font-size:11pt">可以支持其他多种http客户端,如httpclientokhttp等通过</span><span
style="background-color:#ffffff; color:#df402a; font-family:SimSun; font-size:11pt">工厂方法模式</span><span
style="background-color:#ffffff; color:#7b5ba1; font-family:SimSun; font-size:11pt">创建请求</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_345-1566082269458"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_991-1566082211397"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.001.png" width="553" height="144" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_880-1566082349718"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_793-1566082349718"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.002.png" width="553" height="345" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_565-1566082347503"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_974-1566082347716"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_859-1566082347902"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_055-1566082348093"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_542-1566081537855"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.003.png" width="553" height="277" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_721-1566075426884"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_131-1566077535593"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_460-1566077535917"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">restTemplate调用excute方法</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_598-1566077659788"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.004.png" width="553" height="271" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_383-1566077653687"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">restTemplate调用了doExecute方法</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_000-1566077736808"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.005.png" width="553" height="236" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_340-1566077732786"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">执行请求调用</span><span
style="background-color:#ffffff; color:#df402a; font-family:SimSun; font-size:11pt">ResponseExtractor </span><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">responseExtractor.extractData()对相应结果进行数据提取</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_150-1566078107678"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.006.png" width="553" height="382" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_593-1566078099144"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">调用</span><span
style="color:#df402a; font-family:'Times New Roman'; font-size:11pt">HttpMessageConverterExtractor </span><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">this.delegate.extractData()执行抽取数据的操作</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_666-1566078333273"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.007.png" width="553" height="285" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_657-1566078289591"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">获取response-header的content-type</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_561-1566078994408"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.008.png" width="553" height="316" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_699-1566078994408"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_240-1566078897012"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.009.png" width="553" height="303" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_090-1566078895423"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">判断消息转换器对应的支持媒体类型supportMediaType是否包含该content-type</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_470-1566079766383"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.010.png" width="553" height="275" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_142-1566079701403"></a><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">调用第一个包含该content-type的</span><span
style="background-color:#ffffff; color:#df402a; font-family:SimSun; font-size:11pt">GenericHttpMessageConverter转换数据读取数据</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_247-1566080661650"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.011.png" width="553" height="247" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_813-1566080714156"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_896-1566080714156"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.012.png" width="553" height="308" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:0pt"><span
style="font:7.0pt 'Times New Roman'">&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0;&#xa0; </span><a
name="_223-1566080677140"></a><span style="color:#df402a; font-family:'Times New Roman'; font-size:11pt">读取数据的时候会再一次获取</span><span
style="color:#df402a; font-family:SimSun; font-size:11pt; font-style:italic">response-header的content-type</span><span
style="color:#df402a; font-family:'Times New Roman'; font-size:11pt">的字符集</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:21pt"><a name="_092-1566080909997"></a><span
style="color:#df402a; font-family:'Times New Roman'; font-size:11pt">如果该字符集存在则使用该字符集进行 IO流 =字符串 转换</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_512-1566080804579"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.013.png" width="553" height="294" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_470-1566080966519"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_225-1566080966519"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.014.png" width="553" height="307" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_627-1566078282891"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_729-1566075429719"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_937-1566081177561"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="margin:0pt"><a name="_699-1566081177711"></a><span
style="color:#df402a; font-family:微软雅黑; font-size:15pt; font-weight:bold">案例</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_026-1566075429891"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_059-1566071031255"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.015.png" width="553" height="251" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:42pt"><a name="_176-1566070330576"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:42pt"><a name="_530-1566072661453"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_299-1566072723246"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.016.png" width="367" height="101" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:42pt"><a name="_671-1566072721602"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:12pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:42pt"><a name="_075-1566072855176"></a><span
style="color:#df402a; font-family:'Times New Roman'; font-size:12pt; font-weight:bold">响应头中并没有content-type的header照理说浏览器应该不知道服务端返回的输入流编码如果和浏览器默认的编码不匹配应该会出现乱码但是现在浏览器有编码自动识别功能所以上面的代码没有加content-type的Header也没有问题</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:42pt"><a name="_245-1566072658054"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt; text-indent:42pt"><a name="_872-1566072191117"></a><span
style="font-family:'Times New Roman'; font-size:11pt">          </span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_972-1566072692409"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.017.png" width="439" height="462" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_066-1566072088274"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_580-1566075732276"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_942-1566075732559"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="margin:0pt"><a name="_150-1566075732802"></a><span
style="color:#df402a; font-family:微软雅黑; font-size:15pt; font-weight:bold">实际上下面的做法更规范</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_139-1566072089816"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.018.png" width="553" height="188" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="margin:0pt"><a name="_337-1566070344498"></a><span
style="color:#df402a; font-family:微软雅黑; font-size:15pt; font-weight:bold">源码</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_773-1566073175445"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.019.png" width="553" height="366" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_074-1566085375320"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_689-1566085375320"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.020.png" width="553" height="222" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_837-1566085044019"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_120-1566085034872"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.021.png" width="553" height="127" alt="clipboard.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="margin:0pt"><a name="_080-1566073168924"></a><span style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span>
</p>
<p style="margin:0pt"><a name="_415-1566085038805"></a><span style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span>
</p>
<p style="margin:0pt"><a name="_122-1566085039048"></a><span
style="background-color:#ffffff; color:#df402a; font-family:微软雅黑; font-size:15pt; font-weight:bold">============================原理=====================</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_073-1566070331260"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_256-1566070331284"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_812-1566070331308"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_451-1566070331332"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_130-1566070331359"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_999-1566070331383"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_029-1566070331405"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_074-1566070331428"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_078-1566046874710"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_579-1566047010084"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.022.png" width="553" height="1"
alt="初探RestTemplate--解决中文乱码问题 - mryang125的博客 - CSDN博客.jpg"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_666-1566047010084"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p></div>
</body>
</html>

View File

@ -0,0 +1,280 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta name="generator" content="Aspose.Words for .NET 15.1.0.0"/>
<title>服务器跨域处理</title></head>
<body>
<div><p style="margin:0pt"><a name="_073-1565689474241"></a><span
style="font-family:微软雅黑; font-size:15pt; font-weight:bold"><a href="http://m.zinglizingli.xyz">跨域处理</a></span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_011-1565689506880"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_400-1565689507090"></a><span
style="font-family:'Times New Roman'; font-size:11pt">跨域是什么浏览器从一个域名的网页去请求另一个域名的资源时域名端口 协议任一不同都是跨域 我们是采用前后端分离开发的也是前后端分离部署的必然会存在跨域问题 怎么解决跨域很简单只需要在controller类上添加注解 @CrossOrigin 即可这个注解其实是CORS的实现 </span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_460-1565689522680"></a><span
style="font-family:'Times New Roman'; font-size:11pt">CORS(Cross-Origin Resource Sharing, 跨源资源共享)是W3C出的一个标准其思 想是使用自定义的HTTP头部让浏览器与服务器进行沟通从而决定请求或响应是应该成 还是应该失败因此要想实现CORS进行跨域需要服务器进行一些设置同时前端也需要做一些配置和分析本文简单的对服务端的配置和前端的一些设置进行分析</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_845-1565689480275"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_065-1565689480471"></a><span
style="font-family:'Times New Roman'; font-size:11pt">1</span><span
style="color:#df402a; font-family:'Times New Roman'; font-size:11pt">在controller类上添加注解 @CrossOrigin表示Controller上的所以方法允许跨域在方法上添加注解 @CrossOrigin表示该方法允许跨域</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_231-1565689931759"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_436-1565689932017"></a><span
style="font-family:'Times New Roman'; font-size:11pt">@Target({ ElementType.METHOD, ElementType.TYPE })</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_134-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">@Retention(RetentionPolicy.RUNTIME)</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_249-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">@Documented</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_993-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">public @interface CrossOrigin {</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_860-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_082-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String[] DEFAULT_ORIGINS = { "*" };</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_340-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_077-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String[] DEFAULT_ALLOWED_HEADERS = { "*" };</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_080-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_672-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    boolean DEFAULT_ALLOW_CREDENTIALS = true;</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_262-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_435-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    long DEFAULT_MAX_AGE = 1800;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_682-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_040-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_925-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_940-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 同origins属性一样</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_047-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_939-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    @AliasFor("origins")</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_774-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String[] value() default {};</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_570-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_575-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_114-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 所有支持域的集合,例如"http://domain1.com"。</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_373-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * &lt;p&gt;这些值都显示在请求头中的Access-Control-Allow-Origin</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_316-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * "*"代表所有域的请求都支持</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_011-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * &lt;p&gt;如果没有定义,所有请求的域都支持</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_880-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * @see #value</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_783-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_681-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    @AliasFor("value")</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_042-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String[] origins() default {};</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_140-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_747-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_226-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 允许请求头中的header默认都支持</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_485-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_047-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String[] allowedHeaders() default {};</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_052-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_280-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_742-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 响应头中允许访问的header默认为空</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_186-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_068-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String[] exposedHeaders() default {};</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_680-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_547-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_089-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 请求支持的方法,例如"{RequestMethod.GET, RequestMethod.POST}"}。</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_880-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 默认支持RequestMapping中设置的方法</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_922-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_840-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    RequestMethod[] methods() default {};</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_090-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_066-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_985-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 是否允许cookie随请求发送使用时必须指定具体的域</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_972-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_119-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    String allowCredentials() default "";</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_127-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_478-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    /**</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_580-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     * 预请求的结果的有效期默认30分钟</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_510-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">     */</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_534-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">    long maxAge() default -1;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_743-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_586-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">}</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_052-1565689932796"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_129-1565689558428"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_873-1565689558663"></a><span
style="font-family:'Times New Roman'; font-size:11pt">2</span><span
style="color:#df402a; font-family:'Times New Roman'; font-size:11pt">配置 CorsFilter(全局配置)</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_025-1565690417616"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_510-1565690417783"></a><span
style="background-color:#ffffff; color:#808000; font-family:SimSun; font-size:11pt">@Configuration</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_314-1565690418407"></a><span
style="background-color:#ffffff; color:#000080; font-family:SimSun; font-size:11pt; font-weight:bold">public class </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">GlobalCorsConfig {</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_117-1565690418407"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_834-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">    </span><span
style="background-color:#ffffff; color:#808000; font-family:SimSun; font-size:11pt">@Bean</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_074-1565690418407"></a><span
style="background-color:#ffffff; color:#808000; font-family:SimSun; font-size:11pt">    </span><span
style="background-color:#ffffff; color:#000080; font-family:SimSun; font-size:11pt; font-weight:bold">public </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">CorsFilter corsFilter() {</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_037-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">//1.添加CORS配置信息</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_231-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">CorsConfiguration config = </span><span
style="background-color:#ffffff; color:#000080; font-family:SimSun; font-size:11pt; font-weight:bold">new </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">CorsConfiguration();</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_560-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">//1) 允许的域,不要写*否则cookie就无法使用了</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_937-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">config.addAllowedOrigin(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"http://manage.shop.com"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_288-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedOrigin(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"http://www.shop.com"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_712-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">//2) 是否发送Cookie信息</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_250-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">config.setAllowCredentials(</span><span
style="background-color:#ffffff; color:#000080; font-family:SimSun; font-size:11pt; font-weight:bold">true</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_149-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">//3) 允许的请求方式</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_028-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"OPTIONS"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_040-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"HEAD"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_940-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"GET"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_487-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"PUT"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_065-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"POST"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_034-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"DELETE"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_286-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        config.addAllowedMethod(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"PATCH"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_584-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">// 4允许的头信息</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_339-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">config.addAllowedHeader(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"*"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_440-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">// 5) 有效时长</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_023-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">//        config.setMaxAge(3600L);</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_025-1565690418407"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_612-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        //2.添加映射路径,我们拦截一切请求</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_816-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">UrlBasedCorsConfigurationSource configSource = </span><span
style="background-color:#ffffff; color:#000080; font-family:SimSun; font-size:11pt; font-weight:bold">new </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">UrlBasedCorsConfigurationSource();</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_520-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        configSource.registerCorsConfiguration(</span><span
style="background-color:#ffffff; color:#008000; font-family:SimSun; font-size:11pt; font-weight:bold">"/**"</span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">, config);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_929-1565690418407"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_591-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">        </span><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">//3.返回新的CorsFilter.</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_259-1565690418407"></a><span
style="background-color:#ffffff; color:#808080; font-family:SimSun; font-size:11pt; font-style:italic">        </span><span
style="background-color:#ffffff; color:#000080; font-family:SimSun; font-size:11pt; font-weight:bold">return new </span><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">CorsFilter(configSource);</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_877-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">    }</span></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_415-1565690418407"></a><span
style="background-color:#ffffff; font-family:SimSun; font-size:11pt">}</span></p></div>
</body>
</html>

View File

@ -0,0 +1,243 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta name="generator" content="Aspose.Words for .NET 15.1.0.0"/>
<title>对分布式事务的理解</title></head>
<body>
<div><p style="font-size:18pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_848-1565404932800"></a><a
style="color:#000000" href="http://www.zinglizingli.xyz"><span
style="background-color:#ffffff; font-family:Verdana; font-size:18pt">对分布式事务及两阶段提交和三阶段提交的理解</span></a></p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_635-1565404934953"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="margin:0pt 0pt 10pt"><a name="_338-1565404935257"></a><span
style="background-color:#ffffff; color:#008000; font-family:Verdana; font-size:16pt; font-weight:bold">分布式数据一致性</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_989-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在分布式系统中为了保证数据的高可用通常会将数据保留多个副本(replica)这些副本会放置在不同的物理的机器上</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_565-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">1.什么是数据一致性</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_151-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在数据有多份副本的情况下如果网络服务器或者软件出现故障会导致部分副本写入成功部分副本写入失败这就造成各个副本之间的数据不一致数据内容冲突</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_436-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">造成事实上的数据不一致</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_810-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">2.CAP定理</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_066-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">CAP理论认为在分布式的环境下设计和部署系统时有3个核心的需求</span>
</p>
<p style="font-size:12pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_928-1565405011043"></a><span
style="background-color:#ffffff; color:#800000; font-family:Verdana; font-size:12pt; font-weight:bold">ConsistencyAvailability和Partition Tolerance即CAP</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_842-1565405011043"></a><span
style="font-family:'Times New Roman'; font-size:11pt">&#xa0;</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_811-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">Consistency一致性这个和数据库ACID的一致性类似但这里关注的所有数据节点上的数据一致性和正确性而数据库的ACID关注的是在在一个事务内对数据的一些约束系统在执行过某项操作后仍然处于一致的状态在分布式系统中更新操作执行成功后所有的用户都应该读取到最新值</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_016-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">Availability可用性每一个操作总是能够在一定时间内返回结果需要注意一定时间返回结果一定时间是指系统结果必须在给定时间内返回返回结果是指系统返回操作成功或失败的结果</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_115-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">Partition Tolerance分区容忍性是否可以对数据进行分区这是考虑到性能和可伸缩性</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_237-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">3.数据一致性模型</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_943-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">一些分布式系统通过复制数据来提高系统的可靠性和容错性并且将数据的不同的副本存放在不同的机器</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_047-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">强一致性</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_172-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">当更新操作完成之后任何多个后续进程或者线程的访问都会返回最新的更新过的值这种是对用户最友好的就是用户上一次写什么下一次就保证能读到什么根据 CAP 理论这种实现需要牺牲可用性</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_182-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">弱一致性</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_317-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">系统并不保证续进程或者线程的访问都会返回最新的更新过的值用户读到某一操作对系统特定数据的更新需要一段时间我们称这段时间为不一致性窗口系统在数据写入成功之后不承诺立即可以读到最新写入的值也不会具体的承诺多久之后可以读到</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_443-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">最终一致性</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_483-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">是弱一致性的一种特例系统保证在没有后续更新的前提下系统最终返回上一次更新操作的值在没有故障发生的前提下不一致窗口的时间主要受通信延迟系统负载和复制副本的个数影响DNS 是一个典型的最终一致性系统</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_856-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">&#xa0;</span></p>
<p style="margin:0pt 0pt 10pt"><a name="_788-1565405011043"></a><span
style="background-color:#ffffff; color:#008000; font-family:Verdana; font-size:16pt; font-weight:bold">典型的分布式事务实例</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_082-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">跨行转账问题是一个典型的分布式事务用户A向B的一个转账1000要进行A的余额-1000B的余额+1000显然必须保证这两个操作的事务性</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_085-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">类似的还有电商系统中当有用户下单后除了在订单表插入记还要在商品表更新库存等特别是随着微服务架构的流行分布式事务的场景更变得更普遍</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_090-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">&#xa0;</span></p>
<p style="margin:0pt 0pt 10pt"><a name="_157-1565405011043"></a><span
style="background-color:#ffffff; color:#008000; font-family:Verdana; font-size:16pt; font-weight:bold">两阶段提交协议</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_571-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">两阶段提交协议是协调所有分布式原子事务参与者并决定提交或取消回滚的分布式算法</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_016-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">1.协议参与者</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_050-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在两阶段提交协议中系统一般包含两类机器或节点一类为协调者coordinator通常一个系统中只有一个另一类为事务参与者participantscohorts或workers一般包含多个在数据存储系统中可以理解为数据副本的个数协议中假设每个节点都会记录写前日志write-ahead log并持久性存储即使节点发生故障日志也不会丢失协议中同时假设节点不会发生永久性故障而且任意两个节点都可以互相通信</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_760-1565405011043"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.023.png" width="553" height="358" alt="61-160357634.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_560-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">2.两个阶段的执行</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_474-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">1.请求阶段commit-request phase或称表决阶段voting phase</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_786-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在请求阶段协调者将通知事务参与者准备提交或取消事务然后进入表决过程</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_710-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在表决过程中参与者将告知协调者自己的决策同意事务参与者本地作业执行成功或取消本地作业执行故障</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_125-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">2.提交阶段commit phase</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_067-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在该阶段协调者将基于第一个阶段的投票结果进行决策提交或取消</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_981-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务否则协调者将通知所有的参与者取消事务</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_532-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">参与者在接收到协调者发来的消息后将执行响应的操作</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_080-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">3两阶段提交的缺点</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_646-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">1.同步阻塞问题执行过程中所有参与节点都是事务阻塞型的</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_014-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">当参与者占有公共资源时其他第三方节点访问公共资源不得不处于阻塞状态</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_488-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">2.单点故障由于协调者的重要性一旦协调者发生故障</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_765-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">参与者会一直阻塞下去尤其在第二阶段协调者发生故障那么所有的参与者还都处于锁定事务资源的状态中而无法继续完成事务操作如果是协调者挂掉可以重新选举一个协调者但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_010-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">3.数据不一致在二阶段提交的阶段二中当协调者向参与者发送commit请求之后发生了局部网络异常或者在发送commit请求过程中协调者发生了故障这回导致只有一部分参与者接受到了commit请求</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_785-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">而在这部分参与者接到commit请求之后就会执行commit操作但是其他部分未接到commit请求的机器则无法执行事务提交于是整个分布式系统便出现了数据部一致性的现象</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">4两阶段提交无法解决的问题</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_450-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">当协调者出错同时参与者也出错时两阶段无法保证事务执行的完整性</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_279-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">考虑协调者再发出commit消息之后宕机而唯一接收到这条消息的参与者同时也宕机了</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_793-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">那么即使协调者通过选举协议产生了新的协调者这条事务的状态也是不确定的没人知道事务是否被已经提交</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_037-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">&#xa0;</span></p>
<p style="margin:0pt 0pt 10pt"><a name="_052-1565405011043"></a><span
style="background-color:#ffffff; color:#008000; font-family:Verdana; font-size:16pt; font-weight:bold">三阶段提交协议</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_420-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">三阶段提交协议在协调者和参与者中都引入超时机制并且把两阶段提交协议的第一个阶段拆分成了两步询问然后再锁资源最后真正提交</span>
</p>
<p style="font-size:11pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_180-1565405011043"></a><img
src="9a4a540e-1759-4268-90fa-7fb652c3604a.024.png" width="553" height="479" alt="92-920273519.png"
style="-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline"/>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_743-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">1三个阶段的执行</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_294-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">1.CanCommit阶段</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_945-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">3PC的CanCommit阶段其实和2PC的准备阶段很像</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_981-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">协调者向参与者发送commit请求参与者如果可以提交就返回Yes响应否则返回No响应</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_220-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">2.PreCommit阶段</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_740-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_866-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">根据响应情况有以下两种可能</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_992-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">A.假如Coordinator从所有的Cohort获得的反馈都是Yes响应那么就会进行事务的预执行</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_627-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">发送预提交请求Coordinator向Cohort发送PreCommit请求并进入Prepared阶段</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_214-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">事务预提交Cohort接收到PreCommit请求后会执行事务操作并将undo和redo信息记录到事务日志中</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_012-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">响应反馈如果Cohort成功的执行了事务操作则返回ACK响应同时开始等待最终指令</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_068-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">B.假如有任何一个Cohort向Coordinator发送了No响应或者等待超时之后Coordinator都没有接到Cohort的响应那么就中断事务</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_646-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">发送中断请求Coordinator向所有Cohort发送abort请求</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_143-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">中断事务Cohort收到来自Coordinator的abort请求之后或超时之后仍未收到Cohort的请求执行事务的中断</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_223-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">3.DoCommit阶段</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_678-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">该阶段进行真正的事务提交也可以分为以下两种情况:</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_532-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">执行提交</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_431-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">A.发送提交请求Coordinator接收到Cohort发送的ACK响应那么他将从预提交状态进入到提交状态并向所有Cohort发送doCommit请求</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_533-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">B.事务提交Cohort接收到doCommit请求之后执行正式的事务提交并在完成事务提交之后释放所有事务资源</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_010-1565405011043"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">C.响应反馈事务提交完之后向Coordinator发送ACK响应</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_145-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">D.完成事务Coordinator接收到所有Cohort的ACK响应之后完成事务</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_084-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">中断事务</span></p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_752-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">Coordinator没有接收到Cohort发送的ACK响应可能是接受者发送的不是ACK响应也可能响应超时那么就会执行中断事务</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_841-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">2三阶段提交协议和两阶段提交协议的不同</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_499-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制在2PC中只有协调者拥有超时机制即如果在一定时间内没有收到cohort的消息则默认失败</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_629-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">在2PC的准备阶段和提交阶段之间插入预提交阶段使3PC拥有CanCommitPreCommitDoCommit三个阶段</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_049-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">PreCommit是一个缓冲保证了在最后提交阶段之前各参与节点的状态是一致的</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_674-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt; font-weight:bold">2三阶段提交协议的缺点</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_085-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">如果进入PreCommit后Coordinator发出的是abort请求假设只有一个Cohort收到并进行了abort操作</span>
</p>
<p style="font-size:10pt; line-height:115%; margin:0pt 0pt 10pt"><a name="_298-1565405011044"></a><span
style="background-color:#ffffff; font-family:Verdana; font-size:10pt">而其他对于系统状态未知的Cohort会根据3PC选择继续Commit此时系统状态发生不一致性</span>
</p></div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More