Administrator 3 years ago
commit 76cdec07b7

29
.gitignore vendored

@ -0,0 +1,29 @@
# Compiled class file
*.class
classes/
# Log file
*.log
target/
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
*.iml
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
.idea/
.settings/

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,84 @@
# health-manager
#### 介绍
个人健康信息管理系统
#### 软件架构
spring+springmvc+mybatis+mysql+jsp+bootstrap
#### 安装教程
1. 数据库导入sql文件
2. eclipse导入maven项目
3. 设置项目project facets配置版本Dynamic Web Model为[3.0,)
4. 配置web容器导入项目到容器中启动容器
#### 使用说明
1. 访问地址:(http://localhost:{web容器端口}/{项目名称}/)
#### 项目效果
![alt 登录](https://service.beansprout.top/image/health-manager/login.jpg)
![alt 首页](https://service.beansprout.top/image/health-manager/home.jpg)
![alt 健康列表](https://service.beansprout.top/image/health-manager/health_list.jpg)
![alt 健康统计](https://service.beansprout.top/image/health-manager/health_statistics.jpg)
#### 附录
##### Mybatis字段类型映射
```
JDBCType | JavaType
----------------------------
CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
BOOLEAN boolean
TINYINT byte
SMALLINT short
INTEGER int
BIGINT long
REAL float
FLOAT double
DOUBLE double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
CLOB Clob
BLOB Blob
ARRAY Array
DISTINCT mapping of underlying type
STRUCT Struct
REF Ref
DATALINK java.net.URL[color=red][/color]
```
##### SpringMVC 入参校验注解
```
校验注解 可校验类型 具体类型
@AssertTrue Boolean、boolean 属性必须是true
@AssertFalse Boolean、boolean 属性必须是false
@Null 基本类型除外 属性必须为null
@NotNull 基本类型除外 属性必须不能为null
@NotEmpty CharSequence、Collection、Map 属性不能为null字符串和集合长度不能为0无法校验空字符串
@NotBlank CharSequence 属性不能为null并不能为空字符串
@Size CharSequence、Collection、Map 属性长度必须在指定范围
@Length CharSequence 属性长度必须在指定范围
@Min Number 属性必须大于指定最小值
@Max Number 属性必须小于指定最大值
@Range Number 属性在指定返回内
@Past Date、Calender 属性时间必须大于当前时间
@Future Date、Calender 属性时间必须小于当前时间
@Email CharSequence 属性必须是合法邮件格式
@Pattern CharSequence 属性必须匹配正则表达式
```
#### 码云特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

@ -0,0 +1,80 @@
/*
Navicat Premium Data Transfer
Source Server : 127.0.0.1
Source Server Type : MySQL
Source Server Version : 50644
Source Host : localhost:3306
Source Schema : health
Target Server Type : MySQL
Target Server Version : 50644
File Encoding : 65001
Date: 03/05/2020 15:46:09
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_body_info
-- ----------------------------
DROP TABLE IF EXISTS `t_body_info`;
CREATE TABLE `t_body_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`creator` int(11) NULL DEFAULT NULL COMMENT '创建id',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`updater` int(11) NULL DEFAULT NULL COMMENT '修改id',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
`low_blood_pressure` int(10) NULL DEFAULT NULL COMMENT '舒张压',
`high_blood_pressure` int(10) NULL DEFAULT NULL COMMENT '收缩压',
`heart_rate` int(10) NULL DEFAULT NULL COMMENT '心率',
`temperature` double(10, 2) NULL DEFAULT NULL COMMENT '体温',
`appetite` int(11) NULL DEFAULT NULL COMMENT '食欲',
`weight` double(10, 2) NULL DEFAULT NULL COMMENT '体重',
`number_of_step` bigint(20) NULL DEFAULT NULL COMMENT '步数',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '身体信息表' ROW_FORMAT = Compact;
-- ----------------------------
-- Table structure for t_health_config
-- ----------------------------
DROP TABLE IF EXISTS `t_health_config`;
CREATE TABLE `t_health_config` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`creator` int(11) NULL DEFAULT NULL COMMENT '创建人id',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`updater` int(11) NULL DEFAULT NULL COMMENT '修改人',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
`min_low_blood_pressure` int(10) NULL DEFAULT NULL COMMENT '最小低血压',
`max_low_blood_pressure` int(10) NULL DEFAULT NULL COMMENT '最高低血压',
`min_high_blood_pressure` int(10) NULL DEFAULT NULL COMMENT '最小高血压',
`max_high_blood_pressure` int(10) NULL DEFAULT NULL COMMENT '最大高血压',
`min_heart_rate` int(10) NULL DEFAULT NULL COMMENT '最小心率',
`max_heart_rate` int(10) NULL DEFAULT NULL COMMENT '最大心率',
`min_temperature` double(10, 2) NULL DEFAULT NULL COMMENT '最低体温',
`max_temperature` double(10, 2) NULL DEFAULT NULL COMMENT '最高体温',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '健康信息配置表' ROW_FORMAT = Compact;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`creator` int(11) NULL DEFAULT NULL COMMENT '创建人',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`updater` int(11) NULL DEFAULT NULL COMMENT '修改人',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
`nick_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '用户昵称',
`user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '登录账户',
`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '登录密码',
`email` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '邮箱',
`head_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '头像',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `user_name`(`user_name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '用户表' ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;

@ -0,0 +1,239 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>top.beansprout</groupId>
<artifactId>health</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>health-manager</name>
<description>个人健康信息管理系统</description>
<properties>
<project.build.sourceEcoding>UTF-8</project.build.sourceEcoding>
<java.version>1.8</java.version>
<spring.version>5.1.8.RELEASE</spring.version>
<jackson.version>2.10.3</jackson.version>
</properties>
<dependencies>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!--在基础IOC功能上提供扩展服务此外还提供许多企业级服务的支持有邮件服务、任务调度、JNDI定位EJB集成、远程访问、缓存以及多种视图层框架的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 声明式和编程式事务管理 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!--包含SpringMVC框架相关的所有类 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 包含Web应用开发时用到Spring框架时所需的核心类包括自动载入WebApplicationContext特性的类、文件上传的支持类、Filter类和大量工具辅助类 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring context的扩展支持用于MVC方面 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring提供的对AspectJ框架的整合 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring的面向切面编程提供AOP面向切面编程的实现 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- AOP联盟依赖 -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- 下面两个提供对 AspectJ 的支持,是 spring-aspects 所需要依赖的 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>
<!--整合第三方的orm实现如hibernateibatisjdo以及spring 的jpa实现 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!--对JDBC 的简单封装 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<!-- mybatis分页插件依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.0</version>
</dependency>
<!-- 实体类简化工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provider</scope>
</dependency>
<!-- 日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
<!-- lombok依赖项 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!-- json工具效率比fastjson高 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- 工具集 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<!-- springmvc参数校验 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,141 @@
package top.beansprout.health.config;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import lombok.extern.slf4j.Slf4j;
import top.beansprout.health.constant.SysConstant;
import top.beansprout.health.model.vo.RequestVo;
import top.beansprout.health.model.vo.RequestVo.RequestVoBuilder;
import top.beansprout.health.model.vo.UserLoginVo;
import top.beansprout.health.util.JsonUtils;
import top.beansprout.health.util.PublicUtils;
/**
* <p>Title: CrossXssFilter</p>
* <p>Description: </p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/22 22:47
*/
@Slf4j
public class CrossXssFilter implements Filter {
/** 忽略资源地址 **/
private final String[] ignores = new String[] { "/druid", "/static" };
/** 忽略页面地址 **/
private final String[] filtrationViews = new String[] { "/login", "/user/login", "/register", "/user/register",
"/logout", "/user/logout" };
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest request = init(servletRequest);
if (!isRequestValid(request)) {
chain.doFilter(servletRequest, servletResponse);
return;
}
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setContentType("text/html;charset=utf-8");
// sql,xss过滤
log.info("URI:{}", request.getRequestURI());
log.info("METHOD:{}", request.getMethod());
log.info("ParameterMap:{}", JsonUtils.toJson(request.getParameterMap()));
if (isOauthValid(request)) {
// 获取身份
final Object user = request.getSession().getAttribute(SysConstant.INIT_FIELD_USER_VO);
if (PublicUtils.isBlank(user)) {
final HttpServletResponse response = (HttpServletResponse) servletResponse;
if ((request.getHeader("x-requested-with") != null)
&& "XMLHttpRequest".equals(request.getHeader("x-requested-with"))) {
// ajax请求
response.setHeader("sessionstatus", "timeout");
response.setStatus(403);
response.addHeader("loginPath", "login");
chain.doFilter(request, response);
return;
}
// 页面请求
response.setHeader("X-Frame-Options", "DENY");
response.sendRedirect("login");
return;
}
}
final XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper(request);
chain.doFilter(xssHttpServletRequestWrapper, servletResponse);
}
/** 初始化 **/
private HttpServletRequest init(ServletRequest servletRequest) {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final String basePath = PublicUtils.join(request.getScheme(), "://", request.getServerName(),
":" + request.getServerPort(), request.getContextPath(), "/");
final RequestVoBuilder requestVo = RequestVo.builder().basePath(basePath);
final Object userStr = request.getSession().getAttribute(SysConstant.INIT_FIELD_USER_VO);
if (PublicUtils.isNotBlank(userStr)) {
requestVo.user((UserLoginVo) userStr);
}
request.setAttribute(SysConstant.INIT_FIELD_REQUEST_VO, JsonUtils.toJson(requestVo.build()));
return request;
}
/** 校验合法地址请求 **/
private boolean isRequestValid(HttpServletRequest request) {
URI uri;
try {
uri = new URI(request.getRequestURL().toString());
} catch (final URISyntaxException ex) {
return false;
}
if (uri.getHost() == null)
return false;
if (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https"))
return false;
// 忽略指定地址
final String path = StringUtils.removeStart(uri.getPath(), request.getContextPath());
for (final String ignore : ignores) {
if (path.startsWith(ignore))
return false;
}
// 忽略swagger的根路径
if (path.equalsIgnoreCase("/"))
return false;
return true;
}
/** 是否校验合法身份请求 **/
private boolean isOauthValid(HttpServletRequest request) {
// 忽略指定地址
final String path = StringUtils.removeStart(request.getRequestURI(), request.getContextPath());
for (final String filtrationView : filtrationViews) {
if (path.startsWith(filtrationView))
return false;
}
return true;
}
@Override
public void destroy() {
}
}

@ -0,0 +1,43 @@
package top.beansprout.health.config;
import java.util.List;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import top.beansprout.health.model.vo.R;
/**
* <p>Title: ExceptionManager</p>
* <p>Description: </p>
* @author cyy
* @date 2020428
*/
@ControllerAdvice
public class ExceptionManager {
@ResponseBody
@ExceptionHandler({ BindException.class, MethodArgumentNotValidException.class })
public R handleException(Exception e) {
List<FieldError> fieldErrs = null;
if (e instanceof BindException) {
fieldErrs = ((BindException) e).getBindingResult().getFieldErrors();
}
if (e instanceof MethodArgumentNotValidException) {
fieldErrs = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors();
}
Object r = e.getMessage();
if (fieldErrs != null) {
for (final FieldError err : fieldErrs) {
r = err.getDefaultMessage();
break;
}
}
return R.budil().result(false).message(r.toString()).data(r);
}
}

@ -0,0 +1,556 @@
package top.beansprout.health.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Title: HTMLWrapper</p>
* <p>Description: HTML</p>
* HTML filtering utility for protecting against XSS (Cross Site Scripting).
*
* This code is licensed LGPLv3
*
* This code is a Java port of the original work in PHP by Cal Hendersen.
* http://code.iamcal.com/php/lib_filter/
*
* The trickiest part of the translation was handling the differences in regex handling
* between PHP and Java. These resources were helpful in the process:
*
* http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
* http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
* http://www.regular-expressions.info/modifiers.html
*
* A note on naming conventions: instance variables are prefixed with a "v"; global
* constants are in all caps.
*
* Sample use:
* String input = ...
* String clean = new HTMLWrapper().filter( input );
*
* The class is not thread safe. Create a new instance if in doubt.
*
* If you find bugs or have suggestions on improvement (especially regarding
* performance), please contact us. The latest version of this
* source, and our contact details, can be found at http://xss-html-filter.sf.net
*
* @author beansprout
* @date 2020/3/22 23:06
* @version 1.0
*/
@Slf4j
public final class HTMLWrapper {
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
private static final Pattern P_END_ARROW = Pattern.compile("^>");
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
private static final Pattern P_AMP = Pattern.compile("&");
private static final Pattern P_QUOTE = Pattern.compile("<");
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
// @xxx could grow large... maybe use sesat's ReferenceMap
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
/**
* set of allowed html elements, along with allowed attributes for each element
**/
private final Map<String, List<String>> vAllowed;
/**
* counts of open tags for each (allowable) html element
**/
private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
/**
* html elements which must always be self-closing (e.g. "<img />")
**/
private final String[] vSelfClosingTags;
/**
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
**/
private final String[] vNeedClosingTags;
/**
* set of disallowed html elements
**/
private final String[] vDisallowed;
/**
* attributes which should be checked for valid protocols
**/
private final String[] vProtocolAtts;
/**
* allowed protocols
**/
private final String[] vAllowedProtocols;
/**
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
**/
private final String[] vRemoveBlanks;
/**
* entities allowed within html markup
**/
private final String[] vAllowedEntities;
/**
* flag determining whether comments are allowed in input String.
*/
private final boolean stripComment;
private final boolean encodeQuotes;
private boolean vDebug = false;
/**
* flag determining whether to try to make tags when presented with "unbalanced"
* angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false,
* unbalanced angle brackets will be html escaped.
*/
private final boolean alwaysMakeTags;
/**
* Default constructor.
*/
public HTMLWrapper() {
vAllowed = new HashMap<>();
final ArrayList<String> a_atts = new ArrayList<String>();
a_atts.add("href");
a_atts.add("target");
vAllowed.put("a", a_atts);
final ArrayList<String> img_atts = new ArrayList<String>();
img_atts.add("src");
img_atts.add("width");
img_atts.add("height");
img_atts.add("alt");
vAllowed.put("img", img_atts);
final ArrayList<String> no_atts = new ArrayList<String>();
vAllowed.put("b", no_atts);
vAllowed.put("strong", no_atts);
vAllowed.put("i", no_atts);
vAllowed.put("em", no_atts);
vSelfClosingTags = new String[]{"img"};
vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
vDisallowed = new String[]{};
vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
vProtocolAtts = new String[]{"src", "href"};
vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
stripComment = true;
encodeQuotes = true;
alwaysMakeTags = true;
}
/**
* Set debug flag to true. Otherwise use default settings. See the default constructor.
*
* @param debug turn debug on with a true argument
*/
public HTMLWrapper(final boolean debug) {
this();
vDebug = debug;
}
/**
* Map-parameter configurable constructor.
*
* @param conf map containing configuration. keys match field names.
*/
@SuppressWarnings("unchecked")
public HTMLWrapper(final Map<String, Object> conf) {
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
vDisallowed = (String[]) conf.get("vDisallowed");
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
}
private void reset() {
vTagCounts.clear();
}
private void debug(final String msg) {
if (vDebug) {
log.info(msg);
}
}
//---------------------------------------------------------------
// my versions of some PHP library functions
public static String chr(final int decimal) {
return String.valueOf((char) decimal);
}
public static String htmlSpecialChars(final String s) {
String result = s;
result = regexReplace(P_AMP, "&amp;", result);
result = regexReplace(P_QUOTE, "&quot;", result);
result = regexReplace(P_LEFT_ARROW, "&lt;", result);
result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
return result;
}
//---------------------------------------------------------------
/**
* given a user submitted input String, filter out any invalid or restricted
* html.
*
* @param input text (i.e. submitted by a user) than may contain html
* @return "clean" version of input, with only valid, whitelisted html elements allowed
*/
public String filter(final String input) {
reset();
String s = input;
debug("************************************************");
debug(" INPUT: " + input);
s = escapeComments(s);
debug(" escapeComments: " + s);
s = balanceHTML(s);
debug(" balanceHTML: " + s);
s = checkTags(s);
debug(" checkTags: " + s);
s = processRemoveBlanks(s);
debug("processRemoveBlanks: " + s);
s = validateEntities(s);
debug(" validateEntites: " + s);
debug("************************************************\n\n");
return s;
}
public boolean isAlwaysMakeTags() {
return alwaysMakeTags;
}
public boolean isStripComments() {
return stripComment;
}
private String escapeComments(final String s) {
final Matcher m = P_COMMENTS.matcher(s);
final StringBuffer buf = new StringBuffer();
if (m.find()) {
final String match = m.group(1); //(.*?)
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
}
m.appendTail(buf);
return buf.toString();
}
private String balanceHTML(String s) {
if (alwaysMakeTags) {
//
// try and form html
//
s = regexReplace(P_END_ARROW, "", s);
s = regexReplace(P_BODY_TO_END, "<$1>", s);
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
} else {
//
// escape stray brackets
//
s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
//
// the last regexp causes '<>' entities to appear
// (we need to do a lookahead assertion so that the last bracket can
// be used in the next pass of the regexp)
//
s = regexReplace(P_BOTH_ARROWS, "", s);
}
return s;
}
private String checkTags(String s) {
final Matcher m = P_TAGS.matcher(s);
final StringBuffer buf = new StringBuffer();
while (m.find()) {
String replaceStr = m.group(1);
replaceStr = processTag(replaceStr);
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
}
m.appendTail(buf);
s = buf.toString();
// these get tallied in processTag
// (remember to reset before subsequent calls to filter method)
for (final String key : vTagCounts.keySet()) {
for (int ii = 0; ii < vTagCounts.get(key); ii++) {
s += "</" + key + ">";
}
}
return s;
}
private String processRemoveBlanks(final String s) {
String result = s;
for (final String tag : vRemoveBlanks) {
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) {
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
}
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) {
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
}
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
}
return result;
}
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
final Matcher m = regex_pattern.matcher(s);
return m.replaceAll(replacement);
}
private String processTag(final String s) {
// ending tags
Matcher m = P_END_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
if (allowed(name)) {
if (!inArray(name, vSelfClosingTags)) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) - 1);
return "</" + name + ">";
}
}
}
}
// starting tags
m = P_START_TAG.matcher(s);
if (m.find()) {
final String name = m.group(1).toLowerCase();
final String body = m.group(2);
String ending = m.group(3);
//debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
if (allowed(name)) {
String params = "";
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
final List<String> paramNames = new ArrayList<String>();
final List<String> paramValues = new ArrayList<String>();
while (m2.find()) {
paramNames.add(m2.group(1)); //([a-z0-9]+)
paramValues.add(m2.group(3)); //(.*?)
}
while (m3.find()) {
paramNames.add(m3.group(1)); //([a-z0-9]+)
paramValues.add(m3.group(3)); //([^\"\\s']+)
}
String paramName, paramValue;
for (int ii = 0; ii < paramNames.size(); ii++) {
paramName = paramNames.get(ii).toLowerCase();
paramValue = paramValues.get(ii);
// debug( "paramName='" + paramName + "'" );
// debug( "paramValue='" + paramValue + "'" );
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
if (allowedAttribute(name, paramName)) {
if (inArray(paramName, vProtocolAtts)) {
paramValue = processParamProtocol(paramValue);
}
params += " " + paramName + "=\"" + paramValue + "\"";
}
}
if (inArray(name, vSelfClosingTags)) {
ending = " /";
}
if (inArray(name, vNeedClosingTags)) {
ending = "";
}
if ((ending == null) || (ending.length() < 1)) {
if (vTagCounts.containsKey(name)) {
vTagCounts.put(name, vTagCounts.get(name) + 1);
} else {
vTagCounts.put(name, 1);
}
} else {
ending = " /";
}
return "<" + name + params + ending + ">";
} else
return "";
}
// comments
m = P_COMMENT.matcher(s);
if (!stripComment && m.find())
return "<" + m.group() + ">";
return "";
}
private String processParamProtocol(String s) {
s = decodeEntities(s);
final Matcher m = P_PROTOCOL.matcher(s);
if (m.find()) {
final String protocol = m.group(1);
if (!inArray(protocol, vAllowedProtocols)) {
// bad protocol, turn into local anchor link instead
s = "#" + s.substring(protocol.length() + 1, s.length());
if (s.startsWith("#//")) {
s = "#" + s.substring(3, s.length());
}
}
}
return s;
}
private String decodeEntities(String s) {
StringBuffer buf = new StringBuffer();
Matcher m = P_ENTITY.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.decode(match).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENTITY_UNICODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
buf = new StringBuffer();
m = P_ENCODE.matcher(s);
while (m.find()) {
final String match = m.group(1);
final int decimal = Integer.valueOf(match, 16).intValue();
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
}
m.appendTail(buf);
s = buf.toString();
s = validateEntities(s);
return s;
}
private String validateEntities(final String s) {
final StringBuffer buf = new StringBuffer();
// validate entities throughout the string
final Matcher m = P_VALID_ENTITIES.matcher(s);
while (m.find()) {
final String one = m.group(1); //([^&;]*)
final String two = m.group(2); //(?=(;|&|$))
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
}
m.appendTail(buf);
return encodeQuotes(buf.toString());
}
private String encodeQuotes(final String s) {
if (encodeQuotes) {
final StringBuffer buf = new StringBuffer();
final Matcher m = P_VALID_QUOTES.matcher(s);
while (m.find()) {
final String one = m.group(1); //(>|^)
final String two = m.group(2); //([^<]+?)
final String three = m.group(3); //(<|$)
m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
}
m.appendTail(buf);
return buf.toString();
} else
return s;
}
private String checkEntity(final String preamble, final String term) {
return ";".equals(term) && isValidEntity(preamble)
? '&' + preamble
: "&amp;" + preamble;
}
private boolean isValidEntity(final String entity) {
return inArray(entity, vAllowedEntities);
}
private static boolean inArray(final String s, final String[] array) {
for (final String item : array) {
if ((item != null) && item.equals(s))
return true;
}
return false;
}
private boolean allowed(final String name) {
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
}
private boolean allowedAttribute(final String name, final String paramName) {
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
}
}

@ -0,0 +1,77 @@
package top.beansprout.health.config;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import top.beansprout.health.model.vo.BusinessException;
import top.beansprout.health.model.vo.R;
import top.beansprout.health.util.JsonUtils;
import top.beansprout.health.util.PublicUtils;
/**
* <p>Title: MySimpleMappingExceptionResolver</p>
* <p>Description: </p>
* @author cyy
* @date 2020423
*/
public class MySimpleMappingExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception exception) {
// 判断是否ajax请求
if (!((request.getHeader("accept").indexOf("application/json") > -1)
|| ((request.getHeader("X-Requested-With") != null)
&& (request.getHeader("X-Requested-With").indexOf("XMLHttpRequest") > -1)))) {
// 这里需要手动将异常打印出来由于没有配置log实际生产环境应该打印到log里面
exception.printStackTrace();
if (exception instanceof BusinessException) {
final BusinessException be = (BusinessException) exception;
String path = be.getR().getPath();
if (PublicUtils.isBlank(path)) {
path = request.getHeader("Referer");
path = StringUtils.removeStart(path, request.getHeader("Origin"));
path = StringUtils.removeStart(path, request.getContextPath());
}
return R.failed(path, be.getR());
} else
// 对于非ajax请求我们都统一跳转到error.jsp页面
return R.failed(R.budil().result(false).message("系统异常!"));
} else {
// 如果是ajax请求JSON格式返回
if (exception instanceof BusinessException) {
final BusinessException be = (BusinessException) exception;
response(response, be.getR());
} else {
response(response, R.budil().result(false).message("系统异常!"));
}
}
return null;
}
@SuppressWarnings("deprecation")
private void response(HttpServletResponse response, Object data) {
response.setContentType("application/json;charset=UTF-8");
PrintWriter writer = null;
try {
response.setStatus(HttpStatus.OK.value());
writer = response.getWriter();
writer.write(JsonUtils.toJson(data));
writer.flush();
} catch (final IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(writer);
}
}
}

@ -0,0 +1,30 @@
package top.beansprout.health.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
public class TaskExecutorConfig implements AsyncConfigurer { // 1
@Override
public Executor getAsyncExecutor() { // 2
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(10);
taskExecutor.setMaxPoolSize(15);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}

@ -0,0 +1,198 @@
package top.beansprout.health.config;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import top.beansprout.health.util.PublicUtils;
/**
* <p>Title: XssHttpServletRequestWrapper</p>
* <p>Description: XSS</p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/22 22:51
*/
@Slf4j
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest orgRequest;
private final String requestUri;
private static HTMLWrapper htmlWrapper;
@Getter
private String requestBody;
private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+";
private static Set<String> notAllowedKeyWords = new HashSet<>(0);
private static String replacedString = "INVALID";
// 指定uri需要进行html过滤
private static String []htmlUri = { };
private static List<String> ignoreParams = new ArrayList<>();
static {
final String keyStr[] = key.split("\\|");
for (final String str : keyStr) {
notAllowedKeyWords.add(str);
}
htmlWrapper = new HTMLWrapper(true);
}
public XssHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
orgRequest = request;
if (request instanceof XssHttpServletRequestWrapper) {
orgRequest = ((XssHttpServletRequestWrapper) request).getOrgRequest();
}
requestUri = orgRequest.getRequestURI();
requestBody = getAnalysisRequestBody();
}
@Override
public ServletInputStream getInputStream() throws IOException {
// 为空,直接返回
if (PublicUtils.isBlank(requestBody))
return super.getInputStream();
// xss过滤
requestBody = xssEncode(requestBody);
final ByteArrayInputStream bis = new ByteArrayInputStream(requestBody.getBytes("UTF-8"));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return bis.read();
}
};
}
@Override
public String getParameter(String name) {
final String value = super.getParameter(name);
if (value == null)
return null;
return xssEncode(value);
}
@Override
public String[] getParameterValues(String name) {
final String[] parameters = super.getParameterValues(name);
if ((parameters == null) || (parameters.length == 0))
return null;
final int count = parameters.length;
final String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = xssEncode(parameters[i]);
}
return encodedValues;
}
@Override
public Map<String, String[]> getParameterMap() {
final Map<String, String[]> parameters = super.getParameterMap();
if (parameters == null)
return null;
final Map<String, String[]> result = new HashMap<>();
for (final String key : parameters.keySet()) {
final String encodedKey = xssEncode(key);
final int count = parameters.get(key).length;
final String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = xssEncode(parameters.get(key)[i]);
}
result.put(encodedKey, encodedValues);
}
return result;
}
/**
* getHeaderxss
* super.getHeaders(name)
* getHeaderNames
*/
@Override
public String getHeader(String name) {
final String value = super.getHeader(name);
if (value == null)
return null;
// 忽略指定字段不进行xss
if (ignoreParams.contains(name)) return value;
return xssEncode(value);
}
/** 获取请求body json 内容 **/
private String getAnalysisRequestBody() throws IOException {
final String contentType = super.getHeader("Content-Type");
if (PublicUtils.isBlank(contentType) || !MediaType.APPLICATION_JSON_VALUE.contentEquals(contentType))
return null;
return IOUtils.toString(super.getInputStream(), "UTF-8");
}
/** 获取最原始request **/
private HttpServletRequest getOrgRequest() {
return orgRequest;
}
/** 过滤 */
private String xssEncode(String value) {
// You'll need to remove the spaces from the html entities below
String result = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
result = result.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
result = result.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
result = result.replaceAll("'", "& #39;");
result = result.replaceAll("eval\\((.*)\\)", "");
result = result.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
result = result.replaceAll("script", "");
result = sqlKeyFilterWords(result);
for (int i = 0; i < htmlUri.length; i ++) {
if (requestUri.contains(htmlUri[i])) {
result = htmlWrapper.filter(result);
}
}
return result;
}
/** sql注入过滤 **/
private String sqlKeyFilterWords(String value) {
String paramValue = value;
for (final String keyword : notAllowedKeyWords) {
if ((paramValue.length() > (keyword.length() + 1))
&& (paramValue.contains(" " + keyword) || paramValue.contains(keyword + " ") || paramValue.contains(" " + keyword + " "))) {
paramValue = StringUtils.replace(paramValue, keyword, replacedString);
log.warn("CrosXssFilter 请求参数中包含不允许sql的关键词({});参数:{};过滤后的参数:{}", keyword, value, paramValue);
}
}
return paramValue;
}
}

@ -0,0 +1,31 @@
package top.beansprout.health.constant;
import javax.servlet.http.HttpServletRequest;
import top.beansprout.health.model.vo.RequestVo;
import top.beansprout.health.util.JsonUtils;
import top.beansprout.health.util.PublicUtils;
/**
* <p>Title: SysConstant</p>
* <p>Description: </p>
* @author cyy
* @date 2020423
*/
public class SysConstant {
public static final String CHARACHER = "UTF-8";
public static final String INIT_FIELD_REQUEST_IP = "ip";
public static final String INIT_FIELD_REQUEST_REQUEST_ID = "requestId";
public static final String INIT_FIELD_REQUEST_USER_AGENT = "userAgent";
public static final String INIT_FIELD_REQUEST_BASE_PATH = "basePath";
public static final String INIT_FIELD_REQUEST_VO = "requestVo";
public static final String INIT_FIELD_USER_VO = "user";
/** 获取初始化数据 **/
public static RequestVo getRequestVo(HttpServletRequest request) {
return JsonUtils.toObj(PublicUtils.getAttribute(request, INIT_FIELD_REQUEST_VO), RequestVo.class);
}
}

@ -0,0 +1,36 @@
package top.beansprout.health.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import top.beansprout.health.constant.SysConstant;
import top.beansprout.health.model.vo.BusinessException;
import top.beansprout.health.model.vo.UserLoginVo;
import top.beansprout.health.util.PublicUtils;
/**
* <p> Title: BaseController </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020427 12:36:51
* @Version: 1.0.0
*/
public class BaseController {
@Autowired
private HttpServletRequest request;
public UserLoginVo getUserInfo() {
final Object userObject = request.getSession().getAttribute(SysConstant.INIT_FIELD_USER_VO);
if (PublicUtils.isNotBlank(userObject))
return (UserLoginVo) userObject;
throw new BusinessException("login", "身份信息已过期,请重新登录");
}
public int getUserId() {
return getUserInfo().getId();
}
}

@ -0,0 +1,74 @@
package top.beansprout.health.controller;
import java.util.Date;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import top.beansprout.health.model.dto.BodyInfoQuery;
import top.beansprout.health.model.dto.BodyInfoSaveDto;
import top.beansprout.health.model.vo.R;
import top.beansprout.health.service.HealthService;
/**
* <p>Title: HealthController</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
@Controller
@RequestMapping("/health")
public class HealthController extends BaseController {
@Autowired
private HealthService healthService;
// 保存身体信息
@ResponseBody
@PostMapping("/saveBodyInfo")
public R saveBodyInfo(@RequestBody @Valid BodyInfoSaveDto bodyInfoSaveDto) {
healthService.saveBodyInfo(getUserId(), bodyInfoSaveDto);
return R.okAsAjax();
}
// 身体信息列表
@ResponseBody
@GetMapping("/bodyInfoList")
public R bodyInfoList(@Valid BodyInfoQuery bodyInfoQuery) {
return R.okAsAjax(healthService.bodyInfoList(getUserId(), bodyInfoQuery));
}
// 删除身体信息
@ResponseBody
@DeleteMapping("/{id}")
public R saveBodyInfo(@PathVariable int id) {
healthService.deleteBodyInfo(getUserId(), id);
return R.okAsAjax();
}
// 获取身体信息
@ResponseBody
@GetMapping("/{id}")
public R getBodyInfo(@PathVariable int id) {
return R.okAsAjax(healthService.getBodyInfo(getUserId(), id));
}
// 身体信息统计
@ResponseBody
@GetMapping("/bodyInfoStatistics")
public R bodyInfoStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
return R.okAsAjax(healthService.getBodyStatistics(getUserId(), date));
}
}

@ -0,0 +1,89 @@
package top.beansprout.health.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import top.beansprout.health.model.dto.BodyInfoSaveDto;
import top.beansprout.health.model.dto.UserUpdateInfoDto;
import top.beansprout.health.model.entity.TBodyInfo;
import top.beansprout.health.model.vo.R;
import top.beansprout.health.service.HealthService;
import top.beansprout.health.util.MailUtils;
import javax.validation.Valid;
import java.util.List;
/**
* <p>Title: MailController</p>
* <p>Description: </p>
*
* @author ateenliu
* @date 202246
*/
@Controller
@RequestMapping("/mail")
public class MailController extends BaseController {
@Autowired
private HealthService healthService;
@ResponseBody
@PostMapping(value = "/verification")
public R sendVerificationMail(@Valid String email) {
MailUtils mailUtils = new MailUtils();
String verificationCode = mailUtils.createVertifyCode();
String mailSubject = "个人健康管理平台验证码";
String mailBody = "欢迎使用个人健康管理平台,您的邮箱验证码为:"+verificationCode;
if(mailUtils.sendingMimeMail(email,mailSubject,mailBody))
{
System.out.println("邮件发送成功!");
return R.okAsAjax(verificationCode);
}
else {
System.out.println("邮件发送失败!");
return R.okAsAjax();
}
}
@ResponseBody
@PostMapping(value = "/recentPush")
public R recentPushMail(){
if(getUserInfo().getEmail()==null)
return R.ofAsAjax(true,"暂未绑定邮箱","");
List<TBodyInfo> tBodyInfoList = healthService.recentBodyInfoList(getUserId());
TBodyInfo t = new TBodyInfo();
MailUtils mailUtils = new MailUtils();
String mailSubject = "近期健康报告";
StringBuilder content = new StringBuilder("<html><head></head><body><h2>您的近期报告如下:</h2>");
content.append("<table border=\"1\">");
content.append("<tr><th>打卡时间</th><th>收缩压</th><th>舒张压</th>" +
"<th>心率</th><th>体温</th><th>食欲</th><th>体重</th><th>步数</th></tr>");
for(int i=0;i<tBodyInfoList.size();i++){
t = tBodyInfoList.get(i);
content.append("<tr><td>"+t.getCreateTime()+"</td>"+ "<td>"+t.getHighBloodPressure()+"</td>"
+ "<td>"+t.getLowBloodPressure()+"</td>"+ "<td>"+t.getHeartRate()+"</td>"
+ "<td>"+t.getTemperature()+"度</td>"+ "<td>"+t.getAppetiteDes(t.getAppetite())+"</td>"
+ "<td>"+t.getWeight()+"kg</td>"+ "<td>"+t.getNumberOfStep()+"步</td></tr>");
}
content.append("</table>");
content.append("</body></html>");
if(mailUtils.sendingMimeMail(getUserInfo().getEmail(), mailSubject,content.toString()))
{
System.out.println("邮件发送成功!");
return R.okAsAjax();
}
else {
System.out.println("邮件发送失败!");
return R.okAsAjax();
}
}
}

@ -0,0 +1,71 @@
package top.beansprout.health.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* <p> Title: PageController </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020423 11:15:18
* @Version: 1.0.0
*/
@Controller
public class PageController {
// 根页面
@GetMapping("/")
public String rootView() {
return "redirect:/login";
}
// 登录页面
@GetMapping("/login")
public String loginView() {
return "../../index";
}
// 注册页面
@GetMapping("/register")
public String registerView() {
return "register";
}
// 主页面
@GetMapping("/home")
public String homeView() {
return "home";
}
// 用户信息页面
@GetMapping("/userInfo")
public String userInfoView() {
return "userInfo";
}
// 用户信息页面
@GetMapping("/updatePassword")
public String updatePasswordView() {
return "updatePassword";
}
// 用户身体信息录入页面
@GetMapping("/bodyInfoInput")
public String bodyInfoInputView() {
return "bodyInfoInput";
}
// 用户身体信息列表页面
@GetMapping("/bodyInofList")
public String bodyInofListView() {
return "bodyInofList";
}
// 用户身体信息统计页面
@GetMapping("/bodyInofStatistics")
public String bodyInofStatisticsView() {
return "bodyInofStatistics";
}
}

@ -0,0 +1,74 @@
package top.beansprout.health.controller;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import top.beansprout.health.model.dto.UserLoginDto;
import top.beansprout.health.model.dto.UserRegisterDto;
import top.beansprout.health.model.dto.UserUpdateInfoDto;
import top.beansprout.health.model.dto.UserUpdatePasswordDto;
import top.beansprout.health.model.vo.R;
import top.beansprout.health.service.UserService;
/**
* <p>Title: UserController</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020423
*/
@Controller
@RequestMapping("/user")
public class UserController extends BaseController {
@Autowired
private UserService userService;
// 登录
@ResponseBody
@PostMapping("/login")
public R login(@Valid UserLoginDto userLoginDto) {
return R.okAsAjax(userService.login(userLoginDto));
}
// 注册
@ResponseBody
@PostMapping("/register")
public R register(@Valid UserRegisterDto userRegisterDto) {
userService.register(userRegisterDto);
return R.okAsAjax();
}
// 登出
@GetMapping("/logout")
public String logout(HttpServletRequest request) {
userService.logout(request);
return "redirect:/login?target=redirect";
}
// 修改密码
@ResponseBody
@PutMapping("/updatePassword")
public R updatePassword(HttpServletRequest request, @RequestBody @Valid UserUpdatePasswordDto updatePasswordDto) {
userService.updatePassword(request, getUserId(), updatePasswordDto);
return R.okAsAjax();
}
// 修改用户信息
@ResponseBody
@PostMapping(value = "/updateUserInfo", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R updateUserInfo(@Valid UserUpdateInfoDto userUpdateInfoDto) {
return R.okAsAjax(userService.updateUserInfo(getUserId(), userUpdateInfoDto));
}
}

@ -0,0 +1,43 @@
package top.beansprout.health.mapper;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import top.beansprout.health.model.entity.TBodyInfo;
/**
* <p>Title: TBodyInfoMapper</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
public interface TBodyInfoMapper {
@Insert("INSERT INTO t_body_info (creator, create_time, updater, update_time, low_blood_pressure, "
+ "high_blood_pressure, heart_rate, temperature, appetite, weight, number_of_step) VALUE "
+ "( #{creator},NOW(),#{updater},NOW(),#{lowBloodPressure},#{highBloodPressure},"
+ "#{heartRate},#{temperature},#{appetite},#{weight},#{numberOfStep} )")
int insertByOne(TBodyInfo bodyInfo);
@Select("SELECT COUNT(*) FROM t_body_info WHERE creator = #{creator} AND create_time >= CURDATE() AND create_time <= CONCAT(CURDATE(), '23:59:59')")
int countByOneAsToDay(@Param("creator") int userId);
List<TBodyInfo> selectByUserId(@Param("creator") int userId, @Param("minDate") Date minDate,
@Param("maxDate") Date maxDate);
@Delete("DELETE FROM t_body_info WHERE id = #{id} AND creator = #{creator}")
int deleteByOne(@Param("id") int id, @Param("creator") int userId);
@Select("SELECT * FROM t_body_info WHERE id = #{id} AND creator = #{creator}")
TBodyInfo selectByUserOne(@Param("id") int id, @Param("creator") int userId);
@Select("SELECT * FROM t_body_info WHERE creator = #{creator} LIMIT 7 ")
List<TBodyInfo> selectRecentByUserId(@Param("creator") int userId);
}

@ -0,0 +1,12 @@
package top.beansprout.health.mapper;
/**
* <p>Title: THealthConfigMapper</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
public interface THealthConfigMapper {
}

@ -0,0 +1,36 @@
package top.beansprout.health.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import top.beansprout.health.model.entity.TUser;
/**
* <p> Title: TUserMapper </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020423 9:24:05
* @Version: 1.0.0
*/
public interface TUserMapper {
@Select("SELECT * FROM t_user WHERE user_name = #{userName}")
TUser selectByUserName(@Param("userName") String userName);
@Select("SELECT * FROM t_user WHERE id = #{userId}")
TUser selectById(@Param("userId") int id);
@Insert("INSERT INTO t_user (creator, create_time, updater, update_time, nick_name, user_name, password, head_url) "
+ "VALUE (0, NOW(), 0, NOW(), #{userName}, #{userName}, #{password}, #{headUrl})")
int insertByOne(TUser tUser);
@Update("UPDATE t_user SET updater = #{id}, update_time = NOW(), password = #{password} WHERE id = #{id}")
int updateByOne(TUser tUser);
@Update("UPDATE t_user SET updater = #{id}, update_time = NOW(), nick_name = #{nickName}, email = #{email}, head_url = #{headUrl} WHERE id = #{id}")
int updateByUserInfoOne(TUser tUser);
}

@ -0,0 +1,28 @@
package top.beansprout.health.model.dto;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: BodyInfoQuery</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
@Setter
@Getter
public class BodyInfoQuery extends PageDto {
private static final long serialVersionUID = 1L;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date minDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date maxDate;
}

@ -0,0 +1,46 @@
package top.beansprout.health.model.dto;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Range;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: BodyInfoSaveDto</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
@Setter
@Getter
public class BodyInfoSaveDto implements Serializable {
private static final long serialVersionUID = 80577054311531170L;
@NotNull(message = "低血压不能为空")
@Range(min = 0, max = 200, message = "低血压只能在0到200之间")
private Integer lowBloodPressure;
@NotNull(message = "高血压不能为空")
@Range(min = 0, max = 200, message = "高血压只能在0到200之间")
private Integer highBloodPressure;
@NotNull(message = "心率不能为空")
@Range(min = 40, max = 200, message = "心率只能在40到200之间")
private Integer heartRate;
@NotNull(message = "体温不能为空")
@Range(min = 33, max = 45, message = "体温只能在33到45之间")
private Double temperature;
@NotNull(message = "食欲不能为空")
@Range(min = 1, max = 6, message = "食欲只能在1到6之间")
private Integer appetite;
@NotNull(message = "体重不能为空")
@Range(min = 0, max = 200, message = "体重只能在33到40之间")
private Double weight;
// 步数
private int numberOfStep;
}

@ -0,0 +1,32 @@
package top.beansprout.health.model.dto;
import java.io.Serializable;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: PageDto</p>
* <p>Description: </p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/22 22:32
*/
@Setter
@Getter
public class PageDto implements Serializable {
private static final long serialVersionUID = -1796187511693230421L;
@Min(value = 1, message = "当前页最小页码为1")
private int page = 1;
@Min(value = 1, message = "每页展示条数最小为1")
@Max(value = 100, message = "每页展示条数最大为100")
private int pageSize = 10;
}

@ -0,0 +1,33 @@
package top.beansprout.health.model.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.Length;
import lombok.Getter;
import lombok.Setter;
/**
* <p> Title: UserLoginDto </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020425 8:11:06
* @Version: 1.0.0
*/
@Setter
@Getter
public class UserLoginDto implements Serializable {
private static final long serialVersionUID = 6865880222397602631L;
@NotBlank(message = "账户不能为空")
@Length(max = 20, message = "账户不能超过20位")
private String userName;
@NotBlank(message = "密码不能为空")
@Length(max = 20, message = "密码不能超过20位")
private String passWord;
}

@ -0,0 +1,36 @@
package top.beansprout.health.model.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.Length;
import lombok.Getter;
import lombok.Setter;
/**
* <p> Title: UserRegisterDto </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020426 12:54:09
* @Version: 1.0.0
*/
@Setter
@Getter
public class UserRegisterDto implements Serializable {
private static final long serialVersionUID = -4003225859721099921L;
@NotBlank(message = "用户名或姓名不能为空")
@Length(min = 2, max = 10, message = "用户名或姓名必须在2~10位之间")
private String userName;
@NotBlank(message = "密码不能为空")
@Length(min = 6, max = 10, message = "密码必须在6~10位之间")
private String passWord;
@NotBlank(message = "确认密码不能为空")
@Length(min = 6, max = 10, message = "确认密码必须在6~10位之间")
private String confirmPassWord;
}

@ -0,0 +1,39 @@
package top.beansprout.health.model.dto;
import java.io.Serializable;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;
import org.springframework.web.multipart.MultipartFile;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: UserUpdateInfoDto</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020430
*/
@Setter
@Getter
public class UserUpdateInfoDto implements Serializable {
private static final long serialVersionUID = 7815632813092576575L;
// 昵称
@NotBlank(message = "昵称不能为空")
@Length(min = 2, max = 10, message = "昵称只能为2~10个字符")
private String nickName;
// 邮件
@Email(message = "邮箱格式不正确")
private String email;
// 头像
@NotNull(message = "头像不能为空")
private MultipartFile headUrl;
}

@ -0,0 +1,33 @@
package top.beansprout.health.model.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.Length;
import lombok.Getter;
import lombok.Setter;
/**
* <p> Title: UserUpdatePasswordDto </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020427 12:32:39
* @Version: 1.0.0
*/
@Setter
@Getter
public class UserUpdatePasswordDto implements Serializable {
private static final long serialVersionUID = 8674837059264557849L;
@NotBlank(message = "密码不能为空")
@Length(min = 6, max = 10, message = "密码必须在6~10位之间")
private String passWord;
@NotBlank(message = "确认密码不能为空")
@Length(min = 6, max = 10, message = "确认密码必须在6~10位之间")
private String confirmPassWord;
}

@ -0,0 +1,24 @@
package top.beansprout.health.model.entity;
import java.io.Serializable;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: BaseEntity</p>
* <p>Description: -</p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/22 16:50
*/
@Setter
@Getter
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 4402927657355642335L;
private int id;
}

@ -0,0 +1,30 @@
package top.beansprout.health.model.entity;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: BaseUpdateEntity</p>
* <p>Description: -</p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/23 23:52
*/
@Setter
@Getter
public abstract class BaseInsertEntity extends BaseEntity {
private static final long serialVersionUID = -7314584145079382702L;
private Long creator;// 创建人id
private Date createTime;// 创建时间
public void init(long userId) {
this.creator = userId;
this.createTime = new Date();
}
}

@ -0,0 +1,38 @@
package top.beansprout.health.model.entity;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: BaseUpdateEntity</p>
* <p>Description: -</p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/23 23:52
*/
@Setter
@Getter
public abstract class BaseUpdateEntity extends BaseEntity {
private static final long serialVersionUID = 1620758104430484420L;
private int creator;// 创建人id
private Date createTime;// 创建时间
private int updater;// 更新者id
private Date updateTime;// 更新时间
public void init(int userId) {
this.creator = userId;
this.createTime = new Date();
this.update(userId);
}
public void update(int userId) {
this.updater = userId;
this.updateTime = new Date();
}
}

@ -0,0 +1,56 @@
package top.beansprout.health.model.entity;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* <p>Title: TBodyInfo</p>
* <p>Description: </p>
* @author cyy
* @date 2020427
*/
@Setter
@Getter
public class TBodyInfo extends BaseUpdateEntity {
private static final long serialVersionUID = -7707228772072459981L;
// 打开时间
private Date createTime;
// 舒张压
private int lowBloodPressure;
// 收缩压
private int highBloodPressure;
// 心率
private int heartRate;
// 体温
private double temperature;
// 食欲
private int appetite;
// 体重
private double weight;
// 步数
private int numberOfStep;
public String getAppetiteDes(int appetite){
switch (appetite){
case 1:
return "非常差";
case 2:
return "差";
case 3:
return "一般";
case 4:
return "良好";
case 5:
return "很好";
case 6:
return "非常好";
}
return "";
}
}

@ -0,0 +1,35 @@
package top.beansprout.health.model.entity;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: THealthConfig</p>
* <p>Description: </p>
* @author cyy
* @date 2020427
*/
@Setter
@Getter
public class THealthConfig extends BaseUpdateEntity {
private static final long serialVersionUID = 6928075281678415808L;
// 最小低血压
private int minLowBloodPressure;
// 最大低血压
private int maxLowBloodPressure;
// 最小高血压
private int minHighBloodPressure;
// 最大高血压
private int maxHighBloodPressure;
// 最小心率
private int minHeartRate;
// 最大心率
private int maxHeartRate;
// 最小体温
private double minTemperature;
// 最大体温
private double maxTemperature;
}

@ -0,0 +1,30 @@
package top.beansprout.health.model.entity;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: TUser</p>
* <p>Description: </p>
*
* @author beansprout
* @date 2020422
*/
@Setter
@Getter
public class TUser extends BaseUpdateEntity {
private static final long serialVersionUID = 7849174171033853904L;
// 用户名
private String nickName;
// 账户
private String userName;
// 密码
private String password;
// 邮箱
private String email;
// 头像
private String headUrl;
}

@ -0,0 +1,26 @@
package top.beansprout.health.model.vo;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
/**
* <p>Title: AuthVo</p>
* <p>Description: </p>
*
* @author ateenliu
* @date 202246
*/
public class AuthVo extends Authenticator {
private String username = "";
private String password = "";
public AuthVo(String username, String password) {
this.username = username;
this.password = password;
}
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
}

@ -0,0 +1,65 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: BodyInfoDetailVo</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020428
*/
@Setter
@Getter
public class BodyInfoDetailVo implements Serializable {
private static final long serialVersionUID = -2831120593213278473L;
// id
private int id;
// 打卡时间
private Date createTime;
// 舒张压
private int lowBloodPressure;
// 舒张压状态
private int lowBloodPressureStatus;
// 舒张压描述
private String lowBloodPressureDesc;
// 收缩压
private int highBloodPressure;
// 收缩压状态
private int highBloodPressureStatus;
// 收缩压描述
private String highBloodPressureDesc;
// 血压
private String bloodPressureDesc;
// 心率
private int heartRate;
// 心率状态
private int heartRateStatus;
// 心率描述
private String heartRateDesc;
// 体温
private double temperature;
// 体温状态
private int temperatureStatus;
// 体温描述
private String temperatureDesc;
// 食欲
private int appetite;
// 体重
private double weight;
// 步数
private int numberOfStep;
}

@ -0,0 +1,43 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* <p> Title: BodyInfoStatisticsVo </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020428 11:32:05
* @Version: 1.0.0
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class BodyInfoStatisticsVo implements Serializable {
private static final long serialVersionUID = 8627681890953284164L;
// 类别名字
private List<String> typeNames;
// 类别数据
private List<BodyInfoVo> bodyInfoVos;
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class BodyInfoVo {
// 类别名
private String typeName;
// 数据
private List<Object> datas;
}
}

@ -0,0 +1,34 @@
package top.beansprout.health.model.vo;
import lombok.Getter;
/**
* <p>Title: BusinessException</p>
* <p>Description: </p>
* @author cyy
* @date 2020423
*/
@Getter
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -5846808029174051527L;
private final R r;
public BusinessException() {
r = R.budil().result(false).message("系统异常");
}
public BusinessException(String message) {
r = R.budil().result(false).message(message);
}
public BusinessException(String path, String message) {
r = R.budil().result(false).message(message).path(path);
}
public BusinessException(String message, Object data) {
r = R.budil().result(false).message(message).data(data);
}
}

@ -0,0 +1,73 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import java.util.List;
import com.github.pagehelper.PageInfo;
import lombok.Getter;
import lombok.Setter;
/**
* <p>Title: PageVo</p>
* <p>Description: </p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/22 22:15
*/
@Setter
@Getter
public class PageVo<T extends Object> implements Serializable {
private static final long serialVersionUID = 7039024431017840683L;
// 当前页
private long page;
// 每页展示数量
private long pageSize;
// 是否是第一页true第一
private boolean first = false;
// 是否是最后一页true最后
private boolean last = false;
// 总页数
private int totalPages;
// 总数据条数
private int totalElements;
// 当前页数据条数
private int numberOfElements;
// 数据集
private List<?> content;
public PageVo(int page, int pageSize, int totalElements, List<T> content) {
this.pageSize = pageSize;
this.totalElements = totalElements;
this.page = page <= 0 ? 1 : page;
this.totalPages = totalElements == 0 ? 0
: (totalElements % pageSize) == 0 ? totalElements / pageSize : (totalElements / pageSize) + 1;
this.first = page == 1 ? true : false;
this.last = ((page == this.totalPages) || (content.size() < 1)) ? true : false;
this.content = content;
this.numberOfElements = this.content.size();
}
public PageVo(PageInfo<T> pageInfo) {
this.page = pageInfo.getPageNum();
this.pageSize = pageInfo.getPageSize();
this.totalElements = (int) pageInfo.getTotal();
this.totalPages = pageInfo.getPages();
this.first = page == 1 ? true : false;
this.content = pageInfo.getList();
this.last = ((page == this.totalPages) || (content.size() < 1)) ? true : false;
this.numberOfElements = this.content.size();
}
public static <T> PageVo<T> of(int page, int pageSize, int totalElements, List<T> content) {
return new PageVo<T>(page, pageSize, totalElements, content);
}
public static <T> PageVo<T> of(PageInfo<T> pageInfo) {
return new PageVo<T>(pageInfo);
}
}

@ -0,0 +1,110 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.servlet.ModelAndView;
import lombok.Getter;
import lombok.Setter;
import top.beansprout.health.constant.SysConstant;
/**
* <p>Title: R</p>
* <p>Description: </p>
* @author cyy
* @date 2020423
*/
@Setter
@Getter
public class R extends HashMap<String, Object> implements Serializable {
private static final long serialVersionUID = -7261945562236369523L;
public static final String FIELD_RESULT = "result";
public static final String FIELD_MESSAGE = "message";
public static final String FIELD_DATA = "data";
public static final String FIELD_PATH = "path";
public static final String FAILED_FIELD_REQUEST_ID = SysConstant.INIT_FIELD_REQUEST_REQUEST_ID;
public static final String FAILED_FIELD_TIME_STAMP = "timestamp";
public static final String FAILED_FIELD_PATH = "path";
public static final String FAILED_FIELD_ERROR = "error";
public static final String FAILED_FIELD_ERRORS = "errors";
// 结果
private boolean result;
// 描述
private String message;
// 数据
private Object data;
// 页面
private String path;
public static R budil() {
return new R();
}
public R result(boolean result) {
this.put(FIELD_RESULT, result);
this.result = result;
return this;
}
public R message(String message) {
this.put(FIELD_MESSAGE, message);
this.message = message;
return this;
}
public R data(Object data) {
this.put(FIELD_DATA, data);
this.data = data;
return this;
}
public R path(String path) {
this.put(FIELD_PATH, path);
this.path = path;
return this;
}
public static ModelAndView ok() {
return of("/", null);
}
public static R okAsAjax() {
return okAsAjax(null);
}
public static ModelAndView ok(Map<String, Object> data) {
return of("/", data);
}
public static R okAsAjax(Object data) {
return ofAsAjax(true, "成功", data);
}
public static ModelAndView failed() {
return of("/500", null);
}
public static ModelAndView failed(Map<String, Object> data) {
return of("/500", data);
}
public static ModelAndView failed(String path, Map<String, Object> data) {
return of(path, data);
}
public static ModelAndView of(String path, Map<String, Object> data) {
final ModelAndView modelAndView = new ModelAndView(path, data);
return modelAndView;
}
public static R ofAsAjax(boolean result, String message, Object data) {
return budil().result(result).message(message).data(data);
}
}

@ -0,0 +1,31 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* <p>Title: RequestVo</p>
* <p>Description: </p>
* @author cyy
* @date 2020423
*/
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RequestVo implements Serializable {
private static final long serialVersionUID = -2460516900904070899L;
// 基本项目地址
private String basePath;
// 用户信息
private UserLoginVo user;
}

@ -0,0 +1,36 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* <p>Title: UserInfoVo</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020430
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserInfoVo implements Serializable {
private static final long serialVersionUID = 8389631895704876733L;
// 用户id
private int id;
// 用户名
private String nickName;
// 账户
private String userName;
// 邮箱
private String email;
// 头像
private String headUrl;
}

@ -0,0 +1,33 @@
package top.beansprout.health.model.vo;
import java.io.Serializable;
import lombok.Getter;
import lombok.Setter;
/**
* <p> Title: UserLoginVo </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020425 8:49:19
* @Version: 1.0.0
*/
@Setter
@Getter
public class UserLoginVo implements Serializable {
private static final long serialVersionUID = -7027379021523096696L;
// 用户id
private int id;
// 用户名
private String nickName;
// 账户
private String userName;
// 邮箱
private String email;
// 头像
private String headUrl;
}

@ -0,0 +1,40 @@
package top.beansprout.health.service;
import java.util.Date;
import java.util.List;
import top.beansprout.health.model.dto.BodyInfoQuery;
import top.beansprout.health.model.dto.BodyInfoSaveDto;
import top.beansprout.health.model.entity.TBodyInfo;
import top.beansprout.health.model.vo.BodyInfoDetailVo;
import top.beansprout.health.model.vo.BodyInfoStatisticsVo;
import top.beansprout.health.model.vo.PageVo;
/**
* <p>Title: HealthService</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
public interface HealthService {
/** 保存身体信息 **/
void saveBodyInfo(int userId, BodyInfoSaveDto bodyInfoSaveDto);
/** 获取身体信息列表 **/
PageVo<TBodyInfo> bodyInfoList(int userId, BodyInfoQuery bodyInfoQuery);
/** 删除身体信息 **/
void deleteBodyInfo(int userId, int id);
/** 获取身体信息 **/
BodyInfoDetailVo getBodyInfo(int userId, int id);
/** 获取身体信息统计 **/
BodyInfoStatisticsVo getBodyStatistics(int userId, Date date);
/** 获取惊奇身体信息统计 **/
List<TBodyInfo> recentBodyInfoList(int userId);
}

@ -0,0 +1,37 @@
package top.beansprout.health.service;
import javax.servlet.http.HttpServletRequest;
import top.beansprout.health.model.dto.UserLoginDto;
import top.beansprout.health.model.dto.UserRegisterDto;
import top.beansprout.health.model.dto.UserUpdateInfoDto;
import top.beansprout.health.model.dto.UserUpdatePasswordDto;
import top.beansprout.health.model.vo.UserInfoVo;
import top.beansprout.health.model.vo.UserLoginVo;
/**
* <p> Title: UserService </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020425 8:01:14
* @Version: 1.0.0
*/
public interface UserService {
/** 登录逻辑 **/
UserLoginVo login(UserLoginDto userLoginDto);
/** 注册逻辑 **/
void register(UserRegisterDto userRegisterDto);
/** 登出 **/
void logout(HttpServletRequest request);
/** 修改密码 **/
void updatePassword(HttpServletRequest request, int userId, UserUpdatePasswordDto updatePasswordDto);
/** 修改用户信息 **/
UserInfoVo updateUserInfo(int userId, UserUpdateInfoDto userUpdateInfoDto);
}

@ -0,0 +1,299 @@
package top.beansprout.health.service.impl;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import top.beansprout.health.mapper.TBodyInfoMapper;
import top.beansprout.health.mapper.THealthConfigMapper;
import top.beansprout.health.model.dto.BodyInfoQuery;
import top.beansprout.health.model.dto.BodyInfoSaveDto;
import top.beansprout.health.model.entity.TBodyInfo;
import top.beansprout.health.model.vo.BodyInfoDetailVo;
import top.beansprout.health.model.vo.BodyInfoStatisticsVo;
import top.beansprout.health.model.vo.BodyInfoStatisticsVo.BodyInfoVo;
import top.beansprout.health.model.vo.BusinessException;
import top.beansprout.health.model.vo.PageVo;
import top.beansprout.health.service.HealthService;
import top.beansprout.health.util.DateUtils;
import top.beansprout.health.util.PublicUtils;
/**
* <p>Title: HealthServiceImpl</p>
* <p>Description: </p>
*
* @author cyy
* @date 2020427
*/
@Service
public class HealthServiceImpl implements HealthService {
@Autowired
private THealthConfigMapper healthConfigMapper;
@Autowired
private TBodyInfoMapper bodyInfoMapper;
@Override
@Transactional
public void saveBodyInfo(int userId, BodyInfoSaveDto bodyInfoSaveDto) {
// 判断今天是否已经录入过
final int countByOneAsToDay = bodyInfoMapper.countByOneAsToDay(userId);
if (countByOneAsToDay > 0)
throw new BusinessException("今天已经打过卡了");
final TBodyInfo tBodyInfo = new TBodyInfo();
PublicUtils.copyBean(bodyInfoSaveDto, tBodyInfo);
tBodyInfo.init(userId);
bodyInfoMapper.insertByOne(tBodyInfo);
}
@Override
public List<TBodyInfo> recentBodyInfoList(int userId){
List<TBodyInfo> tBodyInfoList = bodyInfoMapper.selectRecentByUserId(userId);
return tBodyInfoList;
}
@Override
public PageVo<TBodyInfo> bodyInfoList(int userId, BodyInfoQuery bodyInfoQuery) {
if ((bodyInfoQuery.getMinDate() != null) && (bodyInfoQuery.getMaxDate() != null)) {
if (bodyInfoQuery.getMinDate().after(bodyInfoQuery.getMaxDate()))
throw new BusinessException("最小时间不能大于最大时间");
}
PageHelper.startPage(bodyInfoQuery.getPage(), bodyInfoQuery.getPageSize());
final PageInfo<TBodyInfo> pageInfo = new PageInfo<>(
bodyInfoMapper.selectByUserId(userId, bodyInfoQuery.getMinDate(), bodyInfoQuery.getMaxDate()));
return PageVo.of(pageInfo);
}
@Override
@Transactional
public void deleteBodyInfo(int userId, int id) {
bodyInfoMapper.deleteByOne(id, userId);
}
@Override
public BodyInfoDetailVo getBodyInfo(int userId, int id) {
final TBodyInfo bodyInfo = bodyInfoMapper.selectByUserOne(id, userId);
if (bodyInfo == null)
throw new BusinessException("该身体信息不存在");
BodyInfoDetailVo bodyInfoDetailVo = new BodyInfoDetailVo();
PublicUtils.copyBean(bodyInfo, bodyInfoDetailVo);
bodyInfoDetailVo = bodyInfoCompare(bodyInfoDetailVo);
return bodyInfoDetailVo;
}
/** 健康信息比较 **/
private BodyInfoDetailVo bodyInfoCompare(BodyInfoDetailVo bodyInfoDetailVo) {
// TODO
// 血压
bodyInfoDetailVo = bloodPressureCompare(bodyInfoDetailVo);
// 心率
final int heartRate = bodyInfoDetailVo.getHeartRate();
bodyInfoDetailVo.setHeartRateStatus(heartRateStatus(heartRate));
bodyInfoDetailVo.setHeartRateDesc(statusDesc(bodyInfoDetailVo.getHeartRateStatus()));
// 体温
final double temperature = bodyInfoDetailVo.getTemperature();
bodyInfoDetailVo.setTemperatureStatus(temperatureStatus(temperature));
bodyInfoDetailVo.setTemperatureDesc(statusDesc(bodyInfoDetailVo.getTemperatureStatus()));
return bodyInfoDetailVo;
}
/** 血压判断 **/
private BodyInfoDetailVo bloodPressureCompare(BodyInfoDetailVo bodyInfoDetailVo) {
// 收缩压
// 正常范围收缩压90139mmHg
final int minHighBloodPressure = 90;
final int maxHighBloodPressure = 139;
// 舒张压
// 舒张压6089mmHg
final int minLowBloodPressure = 60;
final int maxLowBloodPressure = 89;
// 高血压成人收缩压≥140mmHg和舒张压≥90mmHg
// 低血压血压低于90/60mmHg
if (bodyInfoDetailVo.getLowBloodPressure() > maxLowBloodPressure) {
bodyInfoDetailVo.setLowBloodPressureStatus(1);
bodyInfoDetailVo.setLowBloodPressureDesc(statusDesc(bodyInfoDetailVo.getLowBloodPressureStatus()));
} else if (bodyInfoDetailVo.getLowBloodPressure() < minLowBloodPressure) {
bodyInfoDetailVo.setLowBloodPressureStatus(-1);
bodyInfoDetailVo.setLowBloodPressureDesc(statusDesc(bodyInfoDetailVo.getLowBloodPressureStatus()));
} else {
bodyInfoDetailVo.setLowBloodPressureDesc(statusDesc(bodyInfoDetailVo.getLowBloodPressureStatus()));
}
if (bodyInfoDetailVo.getHighBloodPressure() > maxHighBloodPressure) {
bodyInfoDetailVo.setHighBloodPressureStatus(1);
bodyInfoDetailVo.setHighBloodPressureDesc(statusDesc(bodyInfoDetailVo.getHighBloodPressureStatus()));
} else if (bodyInfoDetailVo.getHighBloodPressure() < minHighBloodPressure) {
bodyInfoDetailVo.setHighBloodPressureStatus(-1);
bodyInfoDetailVo.setHighBloodPressureDesc(statusDesc(bodyInfoDetailVo.getHighBloodPressureStatus()));
} else {
bodyInfoDetailVo.setHighBloodPressureDesc(statusDesc(bodyInfoDetailVo.getHighBloodPressureStatus()));
}
if ((bodyInfoDetailVo.getLowBloodPressureStatus() == 1)
&& (bodyInfoDetailVo.getHighBloodPressureStatus() == 1)) {
bodyInfoDetailVo.setBloodPressureDesc("该用户为高血压");
} else if ((bodyInfoDetailVo.getLowBloodPressureStatus() == -1)
&& (bodyInfoDetailVo.getHighBloodPressureStatus() == -1)) {
bodyInfoDetailVo.setBloodPressureDesc("该用户为低血压");
} else if ((bodyInfoDetailVo.getLowBloodPressureStatus() == 0)
&& (bodyInfoDetailVo.getHighBloodPressureStatus() == 0)) {
bodyInfoDetailVo.setBloodPressureDesc("该用户血压正常");
}
/*
* if ((bodyInfoDetailVo.getLowBloodPressure() > maxLowBloodPressure) ||
* (bodyInfoDetailVo.getHighBloodPressure() > maxHighBloodPressure)) {
* bodyInfoDetailVo.setLowBloodPressureStatus(1);
* bodyInfoDetailVo.setLowBloodPressureDesc(statusDesc(bodyInfoDetailVo.
* getLowBloodPressureStatus()));
* bodyInfoDetailVo.setHighBloodPressureStatus(1);
* bodyInfoDetailVo.setHighBloodPressureDesc(statusDesc(bodyInfoDetailVo.
* getHighBloodPressureStatus())); } else if
* ((bodyInfoDetailVo.getLowBloodPressure() < minLowBloodPressure) ||
* (bodyInfoDetailVo.getHighBloodPressure() < minHighBloodPressure)) {
* bodyInfoDetailVo.setLowBloodPressureStatus(-1);
* bodyInfoDetailVo.setLowBloodPressureDesc(statusDesc(bodyInfoDetailVo.
* getLowBloodPressureStatus()));
* bodyInfoDetailVo.setHighBloodPressureStatus(-1);
* bodyInfoDetailVo.setHighBloodPressureDesc(statusDesc(bodyInfoDetailVo.
* getHighBloodPressureStatus())); } else {
* bodyInfoDetailVo.setLowBloodPressureDesc(statusDesc(bodyInfoDetailVo.
* getLowBloodPressureStatus()));
* bodyInfoDetailVo.setHighBloodPressureDesc(statusDesc(bodyInfoDetailVo.
* getHighBloodPressureStatus())); }
*/
return bodyInfoDetailVo;
}
/** 心率判断 **/
private int heartRateStatus(int heartRate) {
final int min = 60;
final int max = 80;
final int max1 = 100;
final int max2 = 120;
if (heartRate < min)
return -1;
else if ((heartRate >= min) && (heartRate <= max))
return 0;
else if ((heartRate > max) && (heartRate < max1))
return 1;
else if ((heartRate > max1) && (heartRate < max2))
return 2;
else
return 4;
}
/** 体温判断 **/
private int temperatureStatus(double temperature) {
final Double min = 36.1;
final Double max = 37.3;
final Double max1 = 38.1;
final Double max2 = 39.1;
final Double max3 = 41.1;
if (temperature < min)
return -1;
else if ((temperature >= min) && (temperature <= max))
return 0;
else if ((temperature > max) && (temperature < max1))
return 1;
else if ((temperature > max1) && (temperature < max2))
return 2;
else if ((temperature > max2) && (temperature < max3))
return 3;
else
return 4;
}
/** 状态描述语 **/
private String statusDesc(int status) {
switch (status) {
case -1:
return "低";
case 1:
return "高";
case 2:
return "很高";
case 3:
return "严重";
case 4:
return "非常严重";
default:
return "正常";
}
}
@Override
public BodyInfoStatisticsVo getBodyStatistics(int userId, Date date) {
LocalDateTime now = null;
if (date == null) {
now = LocalDateTime.now();
} else {
now = DateUtils.convertDateToLDT(date);
}
final LocalDateTime startWeekDateTime = DateUtils.getDayStart(DateUtils.getWeekBegin(now));
final Date startWeek = DateUtils.convertLDTToDate(startWeekDateTime);
final Date endWeek = DateUtils.convertLDTToDate(DateUtils.getDayEnd(DateUtils.getWeekEnd(now)));
final List<TBodyInfo> bodyInfos = bodyInfoMapper.selectByUserId(userId, startWeek, endWeek);
final List<BodyInfoVo> bodyInfoVos = fillBodyInfoVo(startWeekDateTime, bodyInfos);
return new BodyInfoStatisticsVo(bodyInfoVos.stream().map(BodyInfoVo::getTypeName).collect(Collectors.toList()),
bodyInfoVos);
}
/** 填充数据 **/
private List<BodyInfoVo> fillBodyInfoVo(LocalDateTime startWeekDateTime, List<TBodyInfo> bodyInfos) {
final List<BodyInfoVo> bodyInfoVos = new ArrayList<>();
final List<Object> lowBloodPressures = new ArrayList<>();
final List<Object> highBloodPressures = new ArrayList<>();
final List<Object> heartRates = new ArrayList<>();
final List<Object> temperatures = new ArrayList<>();
final List<Object> numberOfSetps = new ArrayList<>();
for (int i = 0; i < 7; i++) {
final Long targetTime = DateUtils.getMilliByTime(DateUtils.plus(startWeekDateTime, i, ChronoUnit.DAYS));
boolean isSign = false;
for (final TBodyInfo tBodyInfo : bodyInfos) {
if (targetTime.equals(DateUtils.getMilliByTime(
DateUtils.getDayStart(DateUtils.convertDateToLDT(tBodyInfo.getCreateTime()))))) {
// 已打卡
isSign = true;
lowBloodPressures.add(tBodyInfo.getLowBloodPressure());
highBloodPressures.add(tBodyInfo.getHighBloodPressure());
heartRates.add(tBodyInfo.getHeartRate());
temperatures.add(tBodyInfo.getTemperature());
numberOfSetps.add(tBodyInfo.getNumberOfStep());
break;
}
}
if (!isSign) {
// 未打卡
lowBloodPressures.add(0);
highBloodPressures.add(0);
heartRates.add(0);
temperatures.add(0);
numberOfSetps.add(0);
}
}
bodyInfoVos.add(new BodyInfoVo("舒张压", lowBloodPressures));
bodyInfoVos.add(new BodyInfoVo("收缩压", highBloodPressures));
bodyInfoVos.add(new BodyInfoVo("心率", heartRates));
bodyInfoVos.add(new BodyInfoVo("体温", temperatures));
bodyInfoVos.add(new BodyInfoVo("步数", numberOfSetps));
return bodyInfoVos;
}
}

@ -0,0 +1,151 @@
package top.beansprout.health.service.impl;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.beansprout.health.constant.SysConstant;
import top.beansprout.health.mapper.TUserMapper;
import top.beansprout.health.model.dto.UserLoginDto;
import top.beansprout.health.model.dto.UserRegisterDto;
import top.beansprout.health.model.dto.UserUpdateInfoDto;
import top.beansprout.health.model.dto.UserUpdatePasswordDto;
import top.beansprout.health.model.entity.TUser;
import top.beansprout.health.model.vo.BusinessException;
import top.beansprout.health.model.vo.UserInfoVo;
import top.beansprout.health.model.vo.UserLoginVo;
import top.beansprout.health.service.UserService;
import top.beansprout.health.util.PublicUtils;
/**
* <p> Title: UserServiceImpl </p>
* <p> Description: </p>
*
* @Auther: cyy
* @Date: 2020425 8:02:42
* @Version: 1.0.0
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private HttpServletRequest request;
@Autowired
private TUserMapper userMapper;
@Override
public UserLoginVo login(UserLoginDto userLoginDto) {
final TUser user = userMapper.selectByUserName(userLoginDto.getUserName());
if (PublicUtils.isBlank(user))
throw new BusinessException("用户不存在");
if (!user.getPassword().equalsIgnoreCase(userLoginDto.getPassWord()))
throw new BusinessException("密码不正确");
final UserLoginVo userLoginVo = new UserLoginVo();
PublicUtils.copyBean(user, userLoginVo);
request.getSession().setAttribute(SysConstant.INIT_FIELD_USER_VO, userLoginVo);
return userLoginVo;
}
@Override
@Transactional
public void register(UserRegisterDto userRegisterDto) {
if (!userRegisterDto.getPassWord().equalsIgnoreCase(userRegisterDto.getConfirmPassWord()))
throw new BusinessException("两次密码不一致");
final TUser user = userMapper.selectByUserName(userRegisterDto.getUserName());
if (PublicUtils.isNotBlank(user))
throw new BusinessException("该账户已经注册");
final TUser tUser = new TUser();
tUser.setUserName(userRegisterDto.getUserName());
tUser.setNickName(tUser.getUserName());
tUser.setPassword(userRegisterDto.getPassWord());
tUser.setHeadUrl("static/imgs/default.png"); //默认头像
userMapper.insertByOne(tUser);
}
@Override
public void logout(HttpServletRequest request) {
// 清除session
final Enumeration<String> em = request.getSession().getAttributeNames();
while (em.hasMoreElements()) {
request.getSession().removeAttribute(em.nextElement().toString());
}
request.getSession().invalidate();
// 请求初始化信息
request.removeAttribute(SysConstant.INIT_FIELD_REQUEST_VO);
}
@Override
public void updatePassword(HttpServletRequest request, int userId, UserUpdatePasswordDto updatePasswordDto) {
if (!updatePasswordDto.getPassWord().equalsIgnoreCase(updatePasswordDto.getConfirmPassWord()))
throw new BusinessException("两次密码不一致");
final TUser user = userMapper.selectById(userId);
if (PublicUtils.isBlank(user))
throw new BusinessException("该账户不存在");
user.setPassword(updatePasswordDto.getPassWord());
userMapper.updateByOne(user);
// 清空session数据
logout(request);
}
@Override
public UserInfoVo updateUserInfo(int userId, UserUpdateInfoDto userUpdateInfoDto) {
// 原始文件名
String sourceName = userUpdateInfoDto.getHeadUrl().getOriginalFilename();
final String fileType = sourceName.substring(sourceName.lastIndexOf("."));
if (!".jpg".equals(fileType.toLowerCase()) && !".png".equals(fileType.toLowerCase()))
throw new BusinessException("只能上传jpg、png格式的图片");
// 获取文件上传的路径在webapp下的static/upload/中
final String base = "E:\\Workspaces\\HM_upload\\";
final File fileDir = new File(base);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
// 讲文件上传到upload目录
sourceName = PublicUtils.join(PublicUtils.randomString(10), fileType);
final File upload = new File(PublicUtils.join(base, sourceName));
//System.out.println(upload.toString());
try {
userUpdateInfoDto.getHeadUrl().transferTo(upload);
} catch (final IOException e) {
throw new BusinessException("上传错误");
}
final String relativePath = PublicUtils.join("/HM_upload/", sourceName);
final TUser user = userMapper.selectById(userId);
if (PublicUtils.isBlank(user))
throw new BusinessException("该账户不存在");
user.setNickName(userUpdateInfoDto.getNickName());
user.setEmail(userUpdateInfoDto.getEmail());
user.setHeadUrl(relativePath);
userMapper.updateByUserInfoOne(user);
final UserInfoVo userInfo = new UserInfoVo();
PublicUtils.copyBean(user, userInfo);
refreshSessionUserInfo(userInfo);
return userInfo;
}
/** 刷新session中的用户信息 **/
private void refreshSessionUserInfo(UserInfoVo userInfo) {
final HttpSession session = request.getSession();
final UserLoginVo userLoginVo = (UserLoginVo) session.getAttribute(SysConstant.INIT_FIELD_USER_VO);
PublicUtils.copyBean(userInfo, userLoginVo);
session.setAttribute(SysConstant.INIT_FIELD_USER_VO, userLoginVo);
}
}

@ -0,0 +1,69 @@
package top.beansprout.health.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* <p>Title: CollectionUtils</p>
* <p>Description: </p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/19 22:37
*/
public class CollectionUtils {
/** 判断集合是否为null或者size=0 **/
public static <T> boolean isEmpty(Collection<T> coll) {
return CollectionUtils.isEmpty(coll);
}
public static <T> boolean isNotEmpty(Collection<T> coll) {
return !isEmpty(coll);
}
/**
* Iterable
*
* @param src
* @param mapper
* @return
*/
public static <T, R> List<R> map(final Iterable<T> src, final Function<? super T, ? extends R> mapper) {
final List<R> r = new ArrayList<>();
for (final T t : src) {
r.add(mapper.apply(t));
}
return r;
}
/**
*
* @param key
* @return
*/
public static <T extends Object> List<T> arrayToList(T... key) {
return Arrays.asList(key);
}
/**
* element
*
* @param sourceCollection
* @param collectionFactory
* @return DEST
*/
public static <T, SOURCETYPE extends Collection<T>, DEST extends Collection<T>> DEST
transformElements(SOURCETYPE sourceCollection, Supplier<DEST> collectionFactory) {
final DEST dest = collectionFactory.get();
sourceCollection.forEach(t -> {
dest.add(t);
});
return dest;
}
}

@ -0,0 +1,286 @@
package top.beansprout.health.util;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.Date;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Title: DateUtils</p>
* <p>Description: </p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/19 23:14
*/
@Slf4j
public class DateUtils {
/** HH:mm **/
public static final String HHmm = "HH:mm";
/** HH:mm:ss **/
public static final String HHmmss = "HH:mm:ss";
/** HH:mm:ss a **/
public static final String HHmmssa = "HH:mm:ss a";
/** yyyyMM **/
public static final String yyyyMM = "yyyyMM";
/** yyyyMMdd **/
public static final String yyyyMMdd = "yyyyMMdd";
/** yyyyMMddHH **/
public static final String yyyyMMddHH = "yyyyMMddHH";
/** yyyyMMddHHmm **/
public static final String yyyyMMddHHmm = "yyyyMMddHHmm";
/** yyyyMMddHHmmss **/
public static final String yyyyMMddHHmmss = "yyyyMMddHHmmss";
/** yyyyMMddHHmmss.SSS **/
public static final String yyyyMMddHHmmssSSS = "yyyyMMddHHmmss.SSS";
/** yyyyMMddTHHmmss.SSSZ **/
public static final String yyyyMMddTHHmmssSSSZ = "yyyyMMdd'T'HHmmss.SSS'Z'";
/** MM-dd HH:mm **/
public static final String MMddHHmm_LINE = "MM-dd HH:mm";
/** yyyy-MM **/
public static final String yyyyMM_LINE = "yyyy-MM";
/** yyyy-MM-dd **/
public static final String yyyyMMdd_LINE = "yyyy-MM-dd";
/** yyyy-MM-dd HH **/
public static final String yyyyMMddHH_LINE = "yyyy-MM-dd HH";
/** yyyy-MM-dd HH:mm **/
public static final String yyyyMMddHHmm_LINE = "yyyy-MM-dd HH:mm";
/** yyyy-MM-dd HH:mm:ss **/
public static final String yyyyMMddHHmmss_LINE = "yyyy-MM-dd HH:mm:ss";
/** yyyy-MM-ddTHH:mm:ss **/
public static final String yyyyMMddTHHmmss_LINE = "yyyy-MM-dd'T'HH:mm:ss";
/** yyyy-MM-dd HH:mm:ss.SSS **/
public static final String yyyyMMddHHmmssSSS_LINE = "yyyy-MM-dd HH:mm:ss.SSS";
/** yyyy-MM-ddTHH:mm:ss.SSSZ **/
public static final String yyyyMMddTHHmmssSSSZ_LINE = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
/** yyyy.MM **/
public static final String yyyyMM_POINT = "yyyy.MM";
/** yyyy.MM.dd **/
public static final String yyyyMMdd_POINT = "yyyy.MM.dd";
/** yyyy.MM.dd HH **/
public static final String yyyyMMddHH_POINT = "yyyy.MM.dd HH";
/** yyyy.MM.dd HH:mm **/
public static final String yyyyMMddHHmm_POINT = "yyyy.MM.dd HH:mm";
/** yyyy.MM.dd HH:mm:ss **/
public static final String yyyyMMddHHmmss_POINT = "yyyy.MM.dd HH:mm:ss";
/** yyyy.MM.dd HH:mm:ss.SSS **/
public static final String yyyyMMddHHmmssSSS_POINT = "yyyy.MM.dd HH:mm:ss.SSS";
/** yyyy.MM.ddTHH:mm:ss.SSSZ **/
public static final String yyyyMMddTHHmmssSSSZ_POINT = "yyyy.MM.dd'T'HH:mm:ss.SSS'Z'";
/** MM/dd/yyyy, HH:mm:ss a **/
public static final String MMddyyyyHHmmssa_SLASH = "MM/dd/yyyy, HH:mm:ss a";
/** MM月MM **/
public static final String yyyyMM_SLASH = "yyyy/MM";
/** yyyy/MM/dd **/
public static final String yyyyMMdd_SLASH = "yyyy/MM/dd";
/** yyyy/MM/dd HH **/
public static final String yyyyMMddHH_SLASH = "yyyy/MM/dd HH";
/** yyyy/MM/dd HH:mm **/
public static final String yyyyMMddHHmm_SLASH = "yyyy/MM/dd HH:mm";
/** yyyy/MM/dd HH:mm:ss **/
public static final String yyyyMMddHHmmss_SLASH = "yyyy/MM/dd HH:mm:ss";
/** yyyy/MM/dd HH:mm:ss.SSS **/
public static final String yyyyMMddHHmmssSSS_SLASH = "yyyy/MM/dd HH:mm:ss.SSS";
/** yyyy/MM/ddTHH:mm:ss.SSSZ **/
public static final String yyyyMMddTHHmmssSSSZ_SLASH = "yyyy/MM/dd'T'HH:mm:ss.SSS'Z'";
/** yyyy年MM月 **/
public static final String yyyyMM_UNIT = "yyyy年MM月";
/** yyyy年MM月dd日 **/
public static final String yyyyMMdd_UNIT = "yyyy年MM月dd日";
/** yyyy年MM月dd日 HH **/
public static final String yyyyMMddHH_UNIT = "yyyy年MM月dd日 HH";
/** yyyy年MM月dd日 HH:mm **/
public static final String yyyyMMddHHmm_UNIT = "yyyy年MM月dd日 HH:mm";
/** yyyy年MM月dd日 HH:mm:ss **/
public static final String yyyyMMddHHmmss_UNIT = "yyyy年MM月dd日 HH:mm:ss";
/** yyyy年MM月dd日 HH:mm:ss.SSS **/
public static final String yyyyMMddHHmmssSSS_UNIT = "yyyy年MM月dd日 HH:mm:ss.SSS";
/** yyyy年MM月dd日THH:mm:ss.SSSZ **/
public static final String yyyyMMddTHHmmssSSSZ_UNIT = "yyyy年MM月dd日'T'HH:mm:ss.SSS'Z'";
public static final long SECONDS_TO_MINUTE = 60;
public static final long MINUTES_TO_HOUR = 60;
public static final long HOUR_TO_DAY = 24;
public static final long DAYS_TO_WEEK = 7;
public static final long DAYS_TO_MONTH = 31;
public static final long DAYS_TO_YEAR = 365;
public static final long MONTHES_TO_YEAR = 12;
public static final long SECONDS_TO_HOUR = SECONDS_TO_MINUTE * MINUTES_TO_HOUR;
public static final long SECONDS_TO_DAY = SECONDS_TO_MINUTE * MINUTES_TO_HOUR * HOUR_TO_DAY;
public static final long SECONDS_TO_WEEK = SECONDS_TO_MINUTE * MINUTES_TO_HOUR * HOUR_TO_DAY * DAYS_TO_WEEK;
public static final long SECONDS_TO_MONTH = SECONDS_TO_MINUTE * MINUTES_TO_HOUR * HOUR_TO_DAY * DAYS_TO_MONTH;// 暂定义位每月31天
public static final long SECONDS_TO_YEAR = SECONDS_TO_MINUTE * MINUTES_TO_HOUR * HOUR_TO_DAY * DAYS_TO_YEAR;
private static final String[] weekDaysName = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
private static final String[] weekDaysName_en = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday" };
private static final String[] monthName = { "一月份", "二月份", "三月份", "四月份", "五月份", "六月份", "七月份", "八月份", "九月份", "十月份",
"十一月份", "十二月份" };
/**
* LocalDateTime
* @param str
* @param pattern
* @return
*/
public static LocalDateTime parse(String str, String pattern) {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(str, formatter);
}
/**
* Date
* @param str
* @param pattern
* @return
*/
public static Date parseDate(String str, String pattern) {
return convertLDTToDate(parse(str, pattern));
}
/**
* DateLocalDateTime
* @param date
* @return
*/
public static LocalDateTime convertDateToLDT(Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
/**
* LocalDateTimeDate
*
* @param time
* @return
*/
public static Date convertLDTToDate(LocalDateTime time) {
return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
}
/**
*
* @param time
* @return
*/
public static Long getMilliByTime(LocalDateTime time) {
return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
*
* @param time
* @return
*/
public static Long getSecondsByTime(LocalDateTime time) {
return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
}
/**
*
* @param time
* @param pattern
* @return
*/
public static String formatTime(LocalDateTime time, String pattern) {
return time.format(DateTimeFormatter.ofPattern(pattern));
}
/**
*
* @param pattern
* @return
*/
public static String formatNow(String pattern) {
return formatTime(LocalDateTime.now(), pattern);
}
/**
* ,field,fieldChronoUnit.*
* @param time
* @param number
* @param field
* @return
*/
public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
return time.plus(number, field);
}
/**
* ,field,fieldChronoUnit.*
* @param time
* @param number
* @param field
* @return
*/
public static LocalDateTime minu(LocalDateTime time, long number, TemporalUnit field) {
return time.minus(number, field);
}
/**
* fieldChronoUnit.*
* @param startTime
* @param endTime
* @param field ()
* @return
*/
public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
final Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
if (field == ChronoUnit.YEARS)
return period.getYears();
if (field == ChronoUnit.MONTHS)
return period.getYears() * 12 + period.getMonths();
return field.between(startTime, endTime);
}
/**
* 2017,7,22 00:00
* @param time
* @return
*/
public static LocalDateTime getDayStart(LocalDateTime time) {
return time.withHour(0).withMinute(0).withSecond(0).withNano(0);
}
/**
* 2017,7,22 23:59:59.999999999
* @param time
* @return
*/
public static LocalDateTime getDayEnd(LocalDateTime time) {
return time.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
}
/**
*
* @param time
* @return
*/
public static LocalDateTime getWeekBegin(LocalDateTime time) {
return time.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
}
/**
*
* @param time
* @return
*/
public static LocalDateTime getWeekEnd(LocalDateTime time) {
return time.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
}
}

@ -0,0 +1,57 @@
package top.beansprout.health.util;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Title: JsonUtils</p>
* <p>Description: Json jackson</p>
* @author beansprout
* @date 2020/3/18 23:39
* @version 1.0
*/
@Slf4j
public class JsonUtils {
private final static ObjectMapper objMapper = new ObjectMapper();
/**
* Json
* @param jsonString
* @param clazz
* @param <T>
* @return
*/
public static <T> T toObj(String jsonString, Class<T> clazz) {
objMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
try {
return objMapper.readValue(jsonString, clazz);
} catch (final IOException e) {
log.error("Json string conversion object failed {}", e);
}
return null;
}
/**
* javaBean json
* @param obj
* @return
*/
public static String toJson(Object obj) {
if((obj instanceof Integer) || (obj instanceof Long) || (obj instanceof Float) ||
(obj instanceof Double) || (obj instanceof Boolean) || (obj instanceof String))
return String.valueOf(obj);
try {
return objMapper.writeValueAsString(obj);
} catch (final JsonProcessingException e) {
log.error("Json object conversion string failed {}", e);
}
return null;
}
}

@ -0,0 +1,74 @@
package top.beansprout.health.util;
import top.beansprout.health.model.vo.AuthVo;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class MailUtils {
private Properties props; //系统属性
private Session mailSession; //邮件会话对象
private MimeMessage mimeMsg; //MIME邮件对象
//获取6位随机验证码
public String createVertifyCode(){
String[] letters = new String[] {
"q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m",
"A","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M",
"0","1","2","3","4","5","6","7","8","9"};
String stringBuilder ="";
for (int i = 0; i < 6; i++) {
stringBuilder = stringBuilder + letters[(int)Math.floor(Math.random()*letters.length)];
}
return stringBuilder;
}
public MailUtils() {
AuthVo au = new AuthVo("ateenliu@hunnu.edu.cn","jiAQr2Qp84xWn7GD");
//设置系统属性
props= System.getProperties(); //获得系统属性对象
props.put("mail.smtp.host", "smtp.exmail.qq.com"); //设置SMTP主机
props.put("mail.smtp.port", "465"); //设置服务端口号
props.put("mail.smtp.auth", "true"); //同时通过验证
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//获得邮件会话对象
mailSession = Session.getInstance(props, au);
}
public boolean sendingMimeMail(String MailTo, String MailSubject,
String MailBody) {
try {
//创建MIME邮件对象
mimeMsg=new MimeMessage(mailSession);
//设置发信人
mimeMsg.setFrom(new InternetAddress("ateenliu@hunnu.edu.cn"));
//设置收信人
if(MailTo!=null){
mimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(MailTo));
}
// //设置抄送人
// if(MailCopyTo!=null){
// mimeMsg.setRecipients(Message.RecipientType.CC,InternetAddress.parse(MailCopyTo));
// }
// //设置暗送人
// if(MailBCopyTo!=null){
// mimeMsg.setRecipients(Message.RecipientType.BCC,InternetAddress.parse(MailBCopyTo));
// }
//设置邮件主题
mimeMsg.setSubject(MailSubject,"utf-8");
//设置邮件内容将邮件body部分转化为HTML格式
mimeMsg.setContent(MailBody,"text/html;charset=utf-8");
//发送邮件
Transport.send(mimeMsg);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

@ -0,0 +1,150 @@
package top.beansprout.health.util;
import java.util.Base64;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
/**
* <p>Title: PublicUtils</p>
* <p>Description: </p>
*
* @author beansprout
* @version 1.0
* @date 2020/3/22 17:41
*/
public class PublicUtils {
/**
*
* @param obj
* @return
*/
public static boolean isBlank(Object obj) {
if (obj == null)
return true;
if (obj instanceof String)
return ((String) obj).trim().equals("");
if (obj instanceof CharSequence)
return ((CharSequence) obj).length() == 0;
if (obj instanceof Object[])
return ((Object[]) obj).length == 0;
if (obj instanceof Collection)
return ((Collection<?>) obj).isEmpty();
if (obj instanceof Map)
return ((Map<?, ?>) obj).isEmpty();
return false;
}
/**
*
* @param obj
* @return
*/
public static boolean isNotBlank(Object obj) {
return !isBlank(obj);
}
/**
* +
* @param leng
* @return
*/
public static String randomString(int leng) {
return RandomStringUtils.randomAlphanumeric(leng);
}
/**
*
* @param values
* @return
*/
public static String join(Object ...values) {
if (values.length <= 0) return "";
final StringBuilder stringBuilder = new StringBuilder();
for (final Object value : values) {
stringBuilder.append(value);
}
return stringBuilder.toString();
}
/**
* Base64
* @param value
* @return
*/
public static String encryptBase64(String value) {
if (isBlank(value)) return null;
final byte[] encode = Base64.getEncoder().encode(value.getBytes());
return new String(encode);
}
/**
* Base64
* @param encrypt
* @return
*/
public static String decryptBase64(String encrypt) {
if (isBlank(encrypt)) return null;
final byte[] decode = Base64.getDecoder().decode(encrypt);
return new String(decode);
}
/**
*
* @param request
* @param key
* @return
*/
public static String getAttribute(HttpServletRequest request, String key) {
return getAttribute(request, key, String.class);
}
public static <T> T getAttribute(HttpServletRequest request, String key, Class<T> requiredType) {
if ((request == null) || isBlank(key)) return null;
final Object value = request.getAttribute(key);
return isBlank(value) ? null : castValue(value, requiredType);
}
/** Object类型转换 **/
private static <T> T castValue(Object value, Class<T> requiredType) {
if ((requiredType == Date.class) && (value instanceof Long)) {
value = new Date((Long)value);
}
if (value instanceof Integer) {
final int intValue = (Integer)value;
if (requiredType == Long.class) {
value = (long)intValue;
} else if ((requiredType == Short.class) && (-32768 <= intValue) && (intValue <= 32767)) {
value = (short)intValue;
} else if ((requiredType == Byte.class) && (-128 <= intValue) && (intValue <= 127)) {
value = (byte)intValue;
}
}
if (!requiredType.isInstance(value))
throw new RuntimeException(
"Expected value to be of type: " + requiredType + ", but was " + value.getClass());
else
return requiredType.cast(value);
}
/**
* Bean
* @param source
* @param target
* @return
*/
public static <T extends Object>T copyBean(T source, T target) {
if (isBlank(source) && isBlank(target)) return null;
BeanUtils.copyProperties(source, target);
return target;
}
}

@ -0,0 +1,4 @@
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/health?useUnicode=true&characterEncoding=UTF-8
jdbc.username=health
jdbc.password=health

@ -0,0 +1,32 @@
### set log levels ###
log4j.rootLogger=DEBUG , console , debug , error
### console ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
### log file ###
#log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.debug.File=log.log
#log4j.appender.debug.Append=true
#log4j.appender.debug.Threshold=INFO
#log4j.appender.debug.layout=org.apache.log4j.PatternLayout
#log4j.appender.debug.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
### exception ###
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File=error-log.log
log4j.appender.error.Append=true
log4j.appender.error.Threshold=ERROR
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
###需要声明然后下方才可以使druid sql输出否则会抛出log4j.error.key not found
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %l %c%n%p: %m%n
### druid sql ###
log4j.logger.druid.sql=warn,stdout
log4j.logger.druid.sql.DataSource=warn,stdout
log4j.logger.druid.sql.Connection=warn,stdout
log4j.logger.druid.sql.Statement=warn,stdout
log4j.logger.druid.sql.ResultSet=warn,stdout

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="top.beansprout.health.mapper.TBodyInfoMapper">
<resultMap id="BaseResultMap"
type="top.beansprout.health.model.entity.TBodyInfo">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="creator" property="creator" jdbcType="INTEGER" javaType="int"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="updater" property="updater" jdbcType="INTEGER" javaType="int"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
</resultMap>
<select id="selectByUserId" resultType="top.beansprout.health.model.entity.TBodyInfo">
SELECT * FROM t_body_info
<where>
creator = #{ creator }
<if test="minDate != null">
AND create_time>=#{minDate}
</if>
<if test="maxDate != null">
<![CDATA[ AND create_time<=#{maxDate} ]]>
</if>
</where>
ORDER BY create_time DESC
</select>
</mapper>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="top.beansprout.health.mapper.THealthConfigMapper">
<resultMap id="BaseResultMap"
type="top.beansprout.health.model.entity.THealthConfig">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="creator" property="creator" jdbcType="INTEGER" javaType="int"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="updater" property="updater" jdbcType="INTEGER" javaType="int"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
</resultMap>
</mapper>

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="top.beansprout.health.mapper.TUserMapper">
<resultMap id="BaseResultMap"
type="top.beansprout.health.model.entity.TUser">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="creator" property="creator" jdbcType="INTEGER" javaType="int"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="updater" property="updater" jdbcType="INTEGER" javaType="int"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR" javaType="string"/>
<result column="user_name" property="userName" jdbcType="VARCHAR" javaType="string"/>
<result column="password" property="password" jdbcType="VARCHAR" javaType="string"/>
<result column="email" property="email" jdbcType="VARCHAR" javaType="string"/>
<result column="head_url" property="headUrl" jdbcType="VARCHAR" javaType="string"/>
</resultMap>
</mapper>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置全局属性 -->
<settings>
<!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 使用列别名替换列名 默认:true -->
<setting name="useColumnLabel" value="true" />
<!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<!-- 默认已经配置分页工具 -->
</configuration>

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis -->
<!-- 2.数据库连接池 -->
<bean id="dataSource"
class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url"
value="jdbc:mysql://localhost:3306/health?useUnicode=true&amp;serverTimezone=GMT%2b8" />
<property name="username" value="root" />
<property name="password" value="woshinibaba7823" />
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<value>
helperDialect=mysql
</value>
</property>
</bean>
</array>
</property>
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation"
value="classpath:spring/mybatis-config.xml" />
<!-- 扫描entity包 使用别名 -->
<property name="typeAliasesPackage"
value="top.beansprout.health.model.entity" />
<!-- 扫描sql配置文件:mapper需要的xml文件 -->
<property name="mapperLocations"
value="classpath:mapper/*.xml" />
</bean>
<!-- 4.配置扫描Dao接口包动态实现Dao接口注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<!-- 给出需要扫描Dao接口包 -->
<property name="basePackage"
value="top.beansprout.health.mapper" />
</bean>
</beans>

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启SpringMVC注解模式 -->
<mvc:annotation-driven />
<!--处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 扫描控制层 -->
<context:component-scan
base-package="top.beansprout.health.controller" />
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.InternalResourceView" />
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 配置上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求编码格式 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 上传文件大小(单位:字节) -->
<property name="maxUploadSize" value="50000000"></property>
<!-- 缓冲区大小(单位:KB) -->
<property name="maxInMemorySize" value="10240"></property>
</bean>
<!-- 由于web.xml中设置是由SpringMVC拦截所有请求,于是在读取静态资源文件的时候就会受到影响(说白了就是读不到) -->
<mvc:resources location="/statics/" mapping="/statics/**" />
<!-- 注册验证器 -->
<mvc:annotation-driven validator="validator" />
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
</bean>
</beans>

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="top.beansprout.health.service"/>
<bean id="exceptionHandler" class="top.beansprout.health.config.MySimpleMappingExceptionResolver" />
<!-- 事务管理器对mybatis操作数据库进行事务控制spring使用jdbc的事务控制类-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- spring 事务注解 mode="aspectj"表示采用切面 mode="proxy"表示代理模式(默认)-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 通知映射到上面的事务管理器-->
<tx:advice id="txAdive" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- aop切面并配置切入点入进行事物管理 指向上面的映射 -->
<aop:config>
<aop:pointcut expression="execution(* top.beansprout.health.service.*.*(..))" id="transactionPointcut"/>
<aop:advisor advice-ref="txAdive" pointcut-ref="transactionPointcut"/>
</aop:config>
</beans>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<!-- 引入其他的xml文件 -->
<import resource="classpath:/spring/spring-dao.xml"/>
<import resource="classpath:/spring/spring-service.xml"/>
<context:component-scan
base-package="top.beansprout.health.config" />
<!-- 定时器 -->
<!-- <task:annotation-driven/> -->
<!-- <context:component-scan base-package="top.beansprout.health.tasks"/> -->
</beans>

@ -0,0 +1,71 @@
<%--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--%>
<%@ page session="false" trimDirectiveWhitespaces="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>401 Unauthorized</title>
<style type="text/css">
<!--
BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;font-size:12px;}
H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}
PRE, TT {border: 1px dotted #525D76}
A {color : black;}A.name {color : black;}
-->
</style>
</head>
<body>
<h1>401 Unauthorized</h1>
<p>
You are not authorized to view this page. If you have not changed
any configuration files, please examine the file
<tt>conf/tomcat-users.xml</tt> in your installation. That
file must contain the credentials to let you use this webapp.
</p>
<p>
For example, to add the <tt>admin-gui</tt> role to a user named
<tt>tomcat</tt> with a password of <tt>s3cret</tt>, add the following to the
config file listed above.
</p>
<pre>
&lt;role rolename="admin-gui"/&gt;
&lt;user username="tomcat" password="s3cret" roles="admin-gui"/&gt;
</pre>
<p>
Note that for Tomcat 7 onwards, the roles required to use the host manager
application were changed from the single <tt>admin</tt> role to the
following two roles. You will need to assign the role(s) required for
the functionality you wish to access.
</p>
<ul>
<li><tt>admin-gui</tt> - allows access to the HTML GUI</li>
<li><tt>admin-script</tt> - allows access to the text interface</li>
</ul>
<p>
The HTML interface is protected against CSRF but the text interface is not.
To maintain the CSRF protection:
</p>
<ul>
<li>Users with the <tt>admin-gui</tt> role should not be granted the
<tt>admin-script</tt> role.</li>
<li>If the text interface is accessed through a browser (e.g. for testing
since this interface is intended for tools not humans) then the browser
must be closed afterwards to terminate the session.</li>
</ul>
</body>
</html>

@ -0,0 +1,90 @@
<%--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--%>
<%@ page session="false" trimDirectiveWhitespaces="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>403 Access Denied</title>
<style type="text/css">
<!--
BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;font-size:12px;}
H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;}
PRE, TT {border: 1px dotted #525D76}
A {color : black;}A.name {color : black;}
-->
</style>
</head>
<body>
<h1>403 Access Denied</h1>
<p>
You are not authorized to view this page.
</p>
<p>
By default the Host Manager is only accessible from a browser running on the
same machine as Tomcat. If you wish to modify this restriction, you'll need
to edit the Host Manager's <tt>context.xml</tt> file.
</p>
<p>
If you have already configured the Host Manager application to allow access
and you have used your browsers back button, used a saved book-mark or
similar then you may have triggered the cross-site request forgery (CSRF)
protection that has been enabled for the HTML interface of the Host Manager
application. You will need to reset this protection by returning to the
<a href="<%=request.getContextPath()%>/html">main Host Manager page</a>.
Once you return to this page, you will be able to continue using the Host
Manager application's HTML interface normally. If you continue to see this
access denied message, check that you have the necessary permissions to
access this application.
</p>
<p> If you have not changed
any configuration files, please examine the file
<tt>conf/tomcat-users.xml</tt> in your installation. That
file must contain the credentials to let you use this webapp.
</p>
<p>
For example, to add the <tt>admin-gui</tt> role to a user named
<tt>tomcat</tt> with a password of <tt>s3cret</tt>, add the following to the
config file listed above.
</p>
<pre>
&lt;role rolename="admin-gui"/&gt;
&lt;user username="tomcat" password="s3cret" roles="admin-gui"/&gt;
</pre>
<p>
Note that for Tomcat 7 onwards, the roles required to use the host manager
application were changed from the single <tt>admin</tt> role to the
following two roles. You will need to assign the role(s) required for
the functionality you wish to access.
</p>
<ul>
<li><tt>admin-gui</tt> - allows access to the HTML GUI</li>
<li><tt>admin-script</tt> - allows access to the text interface</li>
</ul>
<p>
The HTML interface is protected against CSRF but the text interface is not.
To maintain the CSRF protection:
</p>
<ul>
<li>Users with the <tt>admin-gui</tt> role should not be granted the
<tt>admin-script</tt> role.</li>
<li>If the text interface is accessed through a browser (e.g. for testing
since this interface is intended for tools not humans) then the browser
must be closed afterwards to terminate the session.</li>
</ul>
</body>
</html>

@ -0,0 +1,60 @@
<jsp:include page="../view/base.jsp" />
<html>
<head>
<title>404 Not found</title>
<style type="text/css">
<!--
BODY {
font-family: Tahoma, Arial, sans-serif;
color: black;
background-color: white;
font-size: 12px;
}
H1 {
font-family: Tahoma, Arial, sans-serif;
color: white;
background-color: #525D76;
font-size: 22px;
}
PRE, TT {
border: 1px dotted #525D76
}
A {
color: black;
}
A.name {
color: black;
}
-->
</style>
</head>
<body>
<h1>404 Not found</h1>
<p>
The page you tried to access (<%=request.getAttribute("javax.servlet.error.request_uri")%>)
${ baseurl }
does not exist.
</p>
<p>The Host Manager application has been re-structured for Tomcat 7
onwards and some URLs have changed. All URLs used to access the
Manager application should now start with one of the following
options:</p>
<ul>
<li><%=request.getContextPath()%>/html for the HTML GUI</li>
<li><%=request.getContextPath()%>/text for the text interface</li>
</ul>
<p>
Note that the URL for the text interface has changed from &quot;<%=request.getContextPath()%>&quot;
to &quot;<%=request.getContextPath()%>/text&quot;.
</p>
<p>You probably need to adjust the URL you are using to access the
Host Manager application. However, there is always a chance you have
found a bug in the Host Manager application. If you are sure you have
found a bug, and that the bug has not already been reported, please
report it to the Apache Tomcat team.</p>
</body>
</html>

@ -0,0 +1,12 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>错误页面</title>
</head>
<body>
<% System.out.print(request.getAttribute("message")); %>
</body>
</html>

@ -0,0 +1,8 @@
<!-- 静态导入和动态导入jsp该jsp都后一步执行编译导致全局设置jsp编码失效引用界面使用变量如果动态include页面无法获取到变量 -->
<%-- <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%> --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<c:set var="baseurl" value="${pageContext.request.contextPath}" />
<c:set var="user" value="${sessionScope.user}" />

@ -0,0 +1,215 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>身体信息录入</title>
<script type="text/javascript" src="static/js/common-css.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Poppins:300,400,700">
<style type="text/css">
.bg-white {
padding-left: 20px;
padding-top: 20px;
}
.bg-white .input-material {
padding-left: 10px;
}
</style>
</head>
<body>
<div class="col-lg-6 bg-white">
<div class="form d-flex align-items-center">
<div class="content">
<div class="form-group">
<span>昵称</span> <input id="body-nickname" class="input-material" type="text" name="nickName" disabled="disabled"
value="${ user.nickName }">
</div>
<div class="form-group">
<span>舒张压</span> <input id="body-low-blood-pressure" class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name="lowBloodPressure" placeholder="请输入舒张压">
<div class="invalid-feedback">舒张压必须在0~200之间</div>
</div>
<div class="form-group">
<span>收缩压</span> <input id="body-high-blood-pressure" class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name="highBloodPressure" placeholder="请输入收缩压">
<div class="invalid-feedback">收缩压必须在0~200之间</div>
</div>
<div class="form-group">
<span>心率</span> <input id="body-heart-rate" class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name="heartRate" placeholder="请输入心率">
<div class="invalid-feedback">心率必须在40~200之间</div>
</div>
<div class="form-group">
<span>体温</span> <input id="body-temperature" class="input-material" type="text" onkeyup="clearNoNum(this)"
oninput="value=value.replace(/[^\d.]/g,'')" name="temperature" placeholder="请输入体温">
<div class="invalid-feedback">体温必须在33~45度之间</div>
</div>
<div class="form-group">
<span>食欲</span> <select id="body-appetite" class="input-material form-control" name="appetite">
<option>-请选择-</option>
<option value="1">非常差</option>
<option value="2">差</option>
<option value="3">一般</option>
<option value="4">良好</option>
<option value="5">很多</option>
<option value="6">非常多</option>
</select>
<div class="invalid-feedback">请选择食欲</div>
</div>
<div class="form-group">
<span>体重KG</span> <input id="body-weight" class="input-material" type="text" onkeyup="clearNoNum(this)" oninput="value=value.replace(/[^\d.]/g,'')"
name="weight" placeholder="请输入体重">
<div class="invalid-feedback">体重必须在0~200之间</div>
</div>
<div class="form-group">
<span>步数</span> <input id="body-number-of-step" class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name=numberOfStep placeholder="请输入步数">
</div>
<div class="form-group">
<button id="submit" type="button" name="submit" class="btn btn-primary">打卡</button>
<button id="reset" type="reset" name="reset" class="btn btn-primary" style="margin-left: 40px">重置</button>
</div>
</div>
</div>
</div>
<script src="static/js/common-js.js"></script>
<script>
$(function() {
/*错误class form-control is-invalid
正确class form-control is-valid*/
var flaglowBloodPressure = false;
var flagHighBloodPressure = false;
var flagHeartRate = false;
var flagTemperature = false;
var flagAppetite = false;
var flagWeight = false;
var lowBloodPressure, highBloodPressure, heartRate, temperature, appetite, weight;
$("#body-low-blood-pressure").change(function() {
lowBloodPressure = $(this).val();
if (lowBloodPressure < 0 || lowBloodPressure > 200) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid");
flaglowBloodPressure = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid");
flaglowBloodPressure = true;
}
})
$("#body-high-blood-pressure").change(function() {
highBloodPressure = $(this).val();
if (highBloodPressure < 0 || highBloodPressure > 200) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid");
flagHighBloodPressure = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid");
flagHighBloodPressure = true;
}
})
$("#body-heart-rate").change(function() {
heartRate = $(this).val();
if (heartRate < 40 || heartRate > 200) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid");
flagHeartRate = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid");
flagHeartRate = true;
}
})
$("#body-temperature").change(function() {
temperature = $(this).val();
if (temperature < 33 || temperature > 45) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid");
flagTemperature = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid");
flagTemperature = true;
}
})
$("#body-appetite").change(function() {
appetite = $(this).val();
if (!appetite || appetite == '-请选择-') {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid");
flagAppetite = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid");
flagAppetite = true;
}
})
$("#body-weight").change(function() {
weight = $(this).val();
if (!weight || weight <0 || weight > 200) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid");
flagWeight = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid");
flagWeight = true;
}
})
$("#submit").click(function() {
if (flaglowBloodPressure && flagHighBloodPressure && flagHeartRate && flagTemperature && flagAppetite && flagWeight) {
$.ajax({
url: "${baseurl}/health/saveBodyInfo",
type: 'POST',
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
'lowBloodPressure': lowBloodPressure,
'highBloodPressure': highBloodPressure,
'heartRate': heartRate,
'temperature': temperature,
'appetite': appetite,
'weight': weight,
'numberOfStep': $("#body-number-of-step").val()
}),
success: function(data) {
alert(data.message)
if (data.result == true) {
$("input").each(function() {
$(this).removeClass("form-control is-invalid").val("");
});
$("#body-appetite").removeClass("is-valid is-invalid").val("-请选择-");
$("#body-nickname").val('${user.nickName}');
} else {
if (data.path) {
top.location.href=data.path;
}
}
}
});
} else {
if (!flaglowBloodPressure) {
$("#body-low-blood-pressure").addClass("form-control is-invalid");
}
if (!flagHighBloodPressure) {
$("#body-high-blood-pressure").addClass("form-control is-invalid");
}
if (!flagHeartRate) {
$("#body-heart-rate").addClass("form-control is-invalid");
}
if (!flagTemperature) {
$("#body-temperature").addClass("form-control is-invalid");
}
if (!flagAppetite) {
$("#body-appetite").addClass("form-control is-invalid");
}
if (!flagWeight) {
$("#body-weight").addClass("form-control is-invalid");
}
}
})
// 重置
$("#reset").click(function() {
$("input").each(function() {
$(this).removeClass("form-control is-invalid").val("");
});
$("#body-appetite").removeClass("is-valid is-invalid").val("-请选择-");
$("#body-nickname").val('${user.nickName}');
})
})
</script>
</body>
</html>

@ -0,0 +1,234 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>用户身体信息列表</title>
<script src="static/js/common-css.js"></script>
<link rel="stylesheet" type="text/css" href="static/css/util/bootstrap-datetimepicker.min.css">
<script src="static/js/common-js.js"></script>
<script type="text/javascript" src="static/js/util/bootstrap-datetimepicker.min.js" charset="UTF-8"></script>
<script type="text/javascript" src="static/js/util/bootstrap-datetimepicker.zh-CN.js" charset="UTF-8"></script>
<style type="text/css">
div.search {
padding: 5px;
}
div.search label {
padding-left: 10px;
padding-right: 10px;
}
div.search .time {
display: inline-block;
width: 200px;
margin-top: 3px;
}
div.search button {
margin-top: -5px;
}
.body-list tr th {
text-align: center;
}
.body-list tbody tr td {
text-align: center;
line-height: 40px;
padding: 2px;
}
.body-list tfoot span {
border: 1px solid #ececec;
width: 15px;
padding-left: 10px;
padding-right: 16px;
text-align: center;
line-height: 25px;
}
</style>
</head>
<body>
<div class="body-list">
<div class="search">
<label>打卡时间 </label>
<input type="text" class="form-control time" id="min-expireTime"> ~
<input type="text" class="form-control time" id="max-expireTime">
<button type="button" onclick="search(this)" class="btn btn-primary">搜索</button>
<button type="button" onclick="list(1, 10)" class="btn btn-info">刷新</button>
</div>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>序号</th>
<th>打卡时间</th>
<th>收缩压</th>
<th>舒张压</th>
<th>心率</th>
<th>体温</th>
<th>操作</th>
</tr>
</thead>
<tbody id="body"></tbody>
<tfoot>
<tr>
<td id="dataInfo" colspan="6" style="text-align: right; border-right: 0px; line-height: 28px;">1/2</td>
<td id="pageInfo" style="text-align: center; border-left: 0px;">
</td>
</tr>
</tfoot>
</table>
</div>
<!-- JavaScript files-->
<script>
//中文包 解决日期组件乱码问题
(function($){
$.fn.datetimepicker.dates['zh-CN'] = {
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
today: "今天",
suffix: [],
meridiem: ["上午", "下午"]
};
}(jQuery));
var pageSize = 10;
$(function() {
$(".time").datetimepicker({
language: "zh-CN",
format: "yyyy-mm-dd", //显示格式
minView: "month", //设置只显示到月份
initialDate: new Date(), //初始化当前日期
autoclose: true, //选中自动关闭
todayBtn: true, //显示今日按钮
clearBtn: true,
pickerPosition: "bottom-left"
});
$("#min-expireTime").on('change', function(ev) {
var startDate = $('#min-expireTime').val();
$("#max-expireTime").datetimepicker('setStartDate', startDate);
$("#min-expireTime").datetimepicker('hide');
});
$("#max-expireTime").on('change', function(ev) {
var startDate = $('#max-expireTime').val();
$("#min-expireTime").datetimepicker('setReturnDate', startDate);
$("#max-expireTime").datetimepicker('hide');
});
list(1, pageSize);
})
function list(page, pageSize, minDate, maxDate) {
$.ajax({
url: "${baseurl}/health/bodyInfoList?page=" + page + "&pageSize=" + pageSize + (minDate ? ("&minDate=" + minDate) :
'') + (maxDate ? ("&maxDate=" + maxDate) : ''),
type: 'GET',
success: function(data) {
if (data.result == false) {
alert(data.message)
return;
}
var content = "";
const list = data.data.content;
const page = data.data.page;
const totalPage = data.data.totalPages;
for (var i = 0; i < list.length; i++) {
content += "<tr>" +
"<td target=" + list[i].id + ">" + ((page - 1) * pageSize + i + 1) + "</td>" +
"<td>" + dateFormat('YYYY-mm-dd HH:MM', new Date(list[i].createTime)) + "</td>" +
"<td>" + list[i].lowBloodPressure + "</td>" +
"<td>" + list[i].highBloodPressure + "</td>" +
"<td>" + list[i].heartRate + "</td>" +
"<td>" + list[i].temperature + "</td>" +
"<td><button onclick='detailBodyInfo(" + list[i].id + ")' type='button' class='btn btn-info'>详情</button> " +
"<button onclick='deleteBodyInfo(" + list[i].id + ", " + page + ", " + data.data.numberOfElements + ", " +
totalPage + ")' type='button' class='btn btn-danger'>删除</button></td>" +
"</tr>";
}
$("#body").empty().append(content);
$("#dataInfo").text("共" + data.data.totalElements + "条 " + data.data.page + "/" + data.data.totalPages + "页");
$("#pageInfo").html('<a href="#" onclick="pagelist(1, ' + totalPage + ', 0)"><span>|&laquo;</span></a>' +
' <a href="#" onclick="pagelist(' + page + ', ' + totalPage + ', -1)"><span>&laquo;</span></a>' +
' <a href="#" onclick="pagelist(' + page + ', ' + totalPage + ', 1)"><span>&raquo;</span></a>' +
' <a href="#" onclick="pagelist(' + totalPage + ', ' + totalPage + ', 0)"><span>&raquo;|</span></a>');
}
});
}
function pagelist(page, totalPage, criticality) {
const newPage = page + criticality;
if (newPage < 1) {
return;
}
if (newPage > totalPage) {
return;
}
list(newPage, pageSize);
}
function deleteBodyInfo(id, page, numberOfElements, totalPage) {
$.ajax({
url: "${baseurl}/health/" + id,
type: 'DELETE',
success: function(data) {
alert(data.message)
// 当前页临界值处理
if (numberOfElements == 1) {
if (totalPage > 1 && page > 1) {
page = page - 1;
}
}
list(page, pageSize);
}
});
}
function search(e) {
const minDate = $("#min-expireTime").val();
const maxDate = $("#max-expireTime").val();
list(1, pageSize, minDate, maxDate);
}
function detailBodyInfo(id) {
const parent = window.parent;
parent.$('#model_in').val(id);
parent.$('#myModal').modal('show');
$.ajax({
url: "${baseurl}/health/" + id,
type: 'GET',
success: function(data) {
if (data.result == true) {
parent.$("#body-low-blood-pressure").val(data.data.lowBloodPressure);
parent.$("#body-low-blood-pressure-desc").text(data.data.lowBloodPressureDesc);
parent.$("#body-high-blood-pressure").val(data.data.highBloodPressure);
parent.$("#body-high-blood-pressure-desc").text(data.data.highBloodPressureDesc);
parent.$("#body-heart-rate").val(data.data.heartRate);
parent.$("#body-heart-rate-desc").text(data.data.heartRateDesc);
parent.$("#body-temperature").val(data.data.temperature);
parent.$("#body-temperature-desc").text(data.data.temperatureDesc);
parent.$("#body-appetite").val(data.data.appetite);
parent.$("#body-weight").val(data.data.weight);
parent.$("#body-number-of-step").val(data.data.numberOfStep);
parent.$("#body-blog-pressure").text(data.data.bloodPressureDesc);
} else {
alert(data.message)
if (data.path) {
top.location.href = data.path;
}
}
}
});
}
</script>
</body>
</html>

@ -0,0 +1,175 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>用户身体信息统计</title>
<script src="static/js/common-css.js"></script>
<link rel="stylesheet" type="text/css" href="static/css/util/bootstrap-datetimepicker.min.css">
<style type="text/css">
.bar {
padding-right: 40px;
z-index: 1000;
}
.bar label {
padding-left: 10px;
padding-right: 10px;
}
.bar #min-expireTime {
display: inline-block;
width: 200px;
margin-top: 3px;
}
.bar .btn-primary {
margin-top: -5px;
}
.bar .btn-info {
float: right;
}
#container {
margin-top: 35px;
padding: 5px;
position: absolute;
min-height: 100%;
height: auto;
width: 100%;
}
</style>
</head>
<body>
<div class="bar">
<label>时间 </label>
<input type="text" class="form-control time" id="min-expireTime">
<button type="button" onclick="search(this)" class="btn btn-primary">搜索</button>
<button type="button" onclick="init()" class="btn btn-info">刷新</button>
<button type="button" onclick="mailPush()" class="btn btn-info">近期推送</button>
</div>
<div id="container"></div>
<script src="static/js/common-js.js"></script>
<script type="text/javascript" src="static/js/util/bootstrap-datetimepicker.min.js"></script>
<script type="text/javascript" src="static/js/util/bootstrap-datetimepicker.zh-CN.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-gl/dist/echarts-gl.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-stat/dist/ecStat.min.js"></script>
<script type="text/javascript">
//中文包 解决日期组件乱码问题
(function($){
$.fn.datetimepicker.dates['zh-CN'] = {
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
today: "今天",
suffix: [],
meridiem: ["上午", "下午"]
};
}(jQuery));
$(".time").datetimepicker({
language: "zh-CN",
format: "yyyy-mm-dd", //显示格式
minView: "month", //设置只显示到月份
initialDate: new Date(), //初始化当前日期
autoclose: true, //选中自动关闭
todayBtn: true, //显示今日按钮
clearBtn: true,
pickerPosition: "bottom-left",
endDate: new Date()
});
function mailPush(){
$.ajax({
url: "${baseurl}/mail/recentPush" ,
type: 'POST',
contentType: false,
processData: false,
success: function(data){
alert(data.message);
}
});
}
function search(e) {
const minDate = $("#min-expireTime").val();
init(minDate);
}
init();
function init(date) {
$.ajax({
url: "${baseurl}/health/bodyInfoStatistics?" + (date ? ("date=" + date) : ''),
type: 'GET',
success: function(data) {
if (data.result == true) {
let option = {
title: {
text: '健康信息图'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: data.data.typeNames,
selected: { "步数": false }
},
toolbox: {
feature: {
saveAsImage: {}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
}],
yAxis: [{
type: 'value'
}]
};
const bodyInfos = data.data.bodyInfoVos;
let series = [];
for (var i = 0; i < bodyInfos.length; i++) {
series.push({
name: bodyInfos[i].typeName,
type: 'line',
stack: '总量',
areaStyle: {},
data: bodyInfos[i].datas
});
}
option["series"] = series;
if (option && typeof option === "object") {
echarts.init(document.getElementById("container")).setOption(option, true);
}
} else {
alert(data.message)
if (data.path) {
top.location.href = data.path;
}
}
}
});
}
</script>
</body>
</html>

@ -0,0 +1,181 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首页</title>
<script src="static/js/common-css.js"></script>
<script type="text/javascript" src="static/js/common-js.js"></script>
<style type="text/css">
.content-top {}
.content-left {
position: absolute;
min-height: 93.6%;
height: auto;
float: left;
width: 10%;
background: #0088ff;
padding-top: 12px;
border-top: 1px solid rgba(0, 0, 0, .125);
}
.content-left .list-group-item {
text-align: center;
padding-left: 10px;
background: #0088ff;
color: #ffffff;
}
.content-right {
float: right;
width: 90%;
background: #f8f8f8;
padding: 15px 15px 0px 15px;
overflow: auto;
}
.body-desc {
color: red;
font-size: 12px;
margin-left: 10px;
line-height: 24px;
}
</style>
</head>
<body>
<div style="width: 100%;">
<!-- 头部栏 -->
<div class="content-top">
<jsp:include page="top.jsp" />
</div>
<!-- 菜单栏 -->
<div class="content-left">
<div class="list-group">
<a href="#" url="bodyInfoInput" class="list-group-item">健康打卡</a>
<a href="#" url="bodyInofList" class="list-group-item">历史记录</a>
<a href="#" url="bodyInofStatistics" class="list-group-item">健康报告</a>
<a href="#" url="updatePassword" class="list-group-item">修改密码</a>
</div>
</div>
<!-- 内容栏 -->
<div class="content-right">
<div class="breadcrumbs" id="breadcrumbs">
<!-- 面包屑导航 -->
<ul class="breadcrumb">
<li>
<a href="home">Home</a>
</li>
<li class="active">/个人信息</li>
</ul>
</div>
<!-- 内容展示页 -->
<div>
<iframe id="iframe-page-content" src="userInfo" width="100%" frameborder="no" border="0" marginwidth="0"
marginheight=" 0" allowtransparency="yes" scrolling="auto" onload="changeFrameHeight(this)"></iframe>
</div>
</div>
</div>
<!-- 模态框Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel">
健康信息详情
</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
&times;
</button>
<input type="hidden" id="model_in" />
</div>
<div class="modal-body">
<div class="form-group">
<span>舒张压</span><span class="body-desc" id="body-low-blood-pressure-desc"></span> <input id="body-low-blood-pressure" disabled class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name="lowBloodPressure" placeholder="请输入舒张压">
<div class="invalid-feedback">舒张压必须在0~200之间</div>
</div>
<div class="form-group">
<span>收缩压</span><span class="body-desc" id="body-high-blood-pressure-desc"></span> <input id="body-high-blood-pressure" disabled class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name="highBloodPressure" placeholder="请输入收缩压">
<div class="invalid-feedback">收缩压必须在0~200之间</div>
</div>
<div class="form-group">
<span>心率</span><span class="body-desc" id="body-heart-rate-desc"></span> <input id="body-heart-rate" disabled class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name="heartRate" placeholder="请输入心率">
<div class="invalid-feedback">心率必须在40~200之间</div>
</div>
<div class="form-group">
<span>体温</span><span class="body-desc" id="body-temperature-desc"></span> <input id="body-temperature" disabled class="input-material" type="text" onkeyup="clearNoNum(this)"
oninput="value=value.replace(/[^\d.]/g,'')" name="temperature" placeholder="请输入体温">
<div class="invalid-feedback">体温必须在33~40度之间</div>
</div>
<div class="form-group">
<span>食欲</span> <select id="body-appetite" disabled class="input-material form-control" name="appetite">
<option>-请选择-</option>
<option value="1">非常差</option>
<option value="2">差</option>
<option value="3">一般</option>
<option value="4">良好</option>
<option value="5">很多</option>
<option value="6">非常多</option>
</select>
<div class="invalid-feedback">请选择食欲</div>
</div>
<div class="form-group">
<span>体重KG</span> <input id="body-weight" disabled class="input-material" type="text" onkeyup="clearNoNum(this)" oninput="value=value.replace(/[^\d.]/g,'')"
name="weight" placeholder="请输入体重">
<div class="invalid-feedback">体重必须在0~200之间</div>
</div>
<div class="form-group">
<span>步数</span> <input id="body-number-of-step" disabled class="input-material" type="text" oninput="value=value.replace(/[^\d]/g,'')"
name=numberOfStep placeholder="请输入步数">
</div>
</div>
<div class="modal-footer">
<span class="body-desc" id="body-blog-pressure" style="position: absolute; left: 0px; margin-left: 20px;"></span>
<button type="button" class="btn btn-default" data-dismiss="modal">关闭
</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal -->
</div>
<script type="text/javascript">
$(function() {
var height = document.documentElement.clientHeight;
document.getElementsByName("content-right").style.height = height + 'px';
});
// 菜单按钮样式
var oldBackground;
$(".list-group-item").on('click', function() {
$(this).css('background', '#add3f7').siblings().css('background', '#0088ff');
oldBackground = $(this).css("background");
$("#iframe-page-content").attr('src', $(this).attr("url"));
$(".active").text('/' + $(this).text());
});
$(".list-group-item").hover(function() {
oldBackground = $(this).css("background");
$(this).css('background', '#add3f7');
}, function() {
$(this).css('background', oldBackground);
});
// 用户信息按钮
function ifram_info(e) {
$(".active").text('/个人信息');
$("#iframe-page-content").attr('src', e);
$(".list-group-item").css('background', '#0088ff');
}
// 自适应页面高度iframe
function changeFrameHeight(that) {
//电脑屏幕高度-iframe上面其他组件的高度
$(that).height(document.documentElement.clientHeight - 146);
}
</script>
</body>
</html>

@ -0,0 +1,150 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>注册</title>
<script src="static/js/common-css.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Poppins:300,400,700">
<link rel="stylesheet" href="static/css/login.css">
</head>
<body>
<div class="page login-page">
<div class="container d-flex align-items-center">
<div class="form-holder has-shadow">
<div class="row">
<!-- Logo & Information Panel-->
<div class="col-lg-6">
<div class="info d-flex align-items-center">
<div class="content">
<div class="logo">
<h1>欢迎注册</h1>
</div>
<p>个人健康信息管理系统</p>
</div>
</div>
</div>
<!-- Form Panel -->
<div class="col-lg-6 bg-white">
<div class="form d-flex align-items-center">
<div class="content">
<div class="form-group">
<input id="register-username" class="input-material" type="text" name="registerUsername" placeholder="请输入用户名/姓名">
<div class="invalid-feedback">
用户名必须在2~10位之间
</div>
</div>
<div class="form-group">
<input id="register-password" class="input-material" type="password" name="registerPassword" placeholder="请输入密码">
<div class="invalid-feedback">
密码必须在6~10位之间
</div>
</div>
<div class="form-group">
<input id="register-passwords" class="input-material" type="password" name="registerPasswords" placeholder="确认密码">
<div class="invalid-feedback">
两次密码必须相同 且在6~10位之间
</div>
</div>
<div class="form-group">
<button id="regbtn" type="button" name="registerSubmit" class="btn btn-primary">注册</button>
</div>
<small>已有账号?</small><a href="login" class="signup">&nbsp;登录</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- JavaScript files-->
<script src="static/js/common-js.js"></script>
<script>
$(function() {
/*错误class form-control is-invalid
正确class form-control is-valid*/
var flagName = false;
var flagPas = false;
var flagPass = false;
/*验证用户名*/
var name, passWord, passWords;
$("#register-username").change(function() {
name = $("#register-username").val();
if (name.length < 2 || name.length > 10) {
$("#register-username").removeClass("form-control is-valid")
$("#register-username").addClass("form-control is-invalid");
flagName = false;
} else {
$("#register-username").removeClass("form-control is-invalid")
$("#register-username").addClass("form-control is-valid");
flagName = true;
}
})
/*验证密码*/
$("#register-password").change(function() {
passWord = $("#register-password").val();
if (passWord.length < 6 || passWord.length > 18) {
$("#register-password").removeClass("form-control is-valid")
$("#register-password").addClass("form-control is-invalid");
flagPas = false;
} else {
$("#register-password").removeClass("form-control is-invalid")
$("#register-password").addClass("form-control is-valid");
flagPas = true;
}
})
/*验证确认密码*/
$("#register-passwords").change(function() {
passWords = $("#register-passwords").val();
if ((passWord != passWords) || (passWords.length < 6 || passWords.length > 18)) {
$("#register-passwords").removeClass("form-control is-valid")
$("#register-passwords").addClass("form-control is-invalid");
flagPass = false;
} else {
$("#register-passwords").removeClass("form-control is-invalid")
$("#register-passwords").addClass("form-control is-valid");
flagPass = true;
}
})
$("#regbtn").click(function() {
if (flagName && flagPas && flagPass) {
$.ajax({
url: "${baseurl}/user/register",
type: 'POST',
data: {
'userName': name,
'passWord': passWord,
'confirmPassWord': passWords
},
success: function(data) {
alert(data.message)
if (data.result == true) {
localStorage.setItem("userName", name);
$("#register-username").val("");
$("#register-username").removeClass("is-valid");
$("#register-password").val("");
$("#register-password").removeClass("is-valid");
$("#register-passwords").val("");
$("#register-passwords").removeClass("is-valid");
window.location.href = 'login';
}
}
});
} else {
if (!flagName) {
$("#register-username").addClass("form-control is-invalid");
}
if (!flagPas) {
$("#register-password").addClass("form-control is-invalid");
}
if (!flagPass) {
$("#register-passwords").addClass("form-control is-invalid");
}
}
})
})
</script>
</body>
</html>

@ -0,0 +1,55 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>头部</title>
<script src="static/js/common-css.js"></script>
<script type="text/javascript" src="static/js/common-js.js"></script>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<style type="text/css">
div.container {
background: #0088ff;
height: 60px;
max-width: 100%;
}
div.container h3 {
float: left;
margin-top: 10px;
margin-left: 10%;
}
div.container h3 a {
color: #ffffff;
}
div.container h3 a:hover {
text-decoration: none;
}
div.container .dropdown {
float: right;
margin-top: 5px;
margin-right: 5%;
}
div.container span img {
width: 50px;
height: 50px;
border-radius: 40px;
}
</style>
</head>
<body>
<div class="container">
<h3><a href="home">个人健康信息管理</a></h3>
<div class="dropdown">
<span class="dropdown-toggle" data-toggle="dropdown"><img src="${ user.headUrl }" /></span>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" onclick="ifram_info('userInfo')">个人信息</a>
<a id="logout" class="dropdown-item" href="user/logout">退出登录</a>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,120 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>修改密码</title>
<script type="text/javascript" src="static/js/common-css.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Poppins:300,400,700">
<style type="text/css">
.bg-white {
padding-left: 20px;
padding-top: 20px;
}
.bg-white .input-material {
padding-left: 10px;
}
</style>
</head>
<body>
<div class="col-lg-6 bg-white">
<div class="form d-flex align-items-center">
<div class="content">
<div class="form-group">
<input id="register-username" class="input-material" type="text" name="userName" placeholder="请输入用户名" disabled="disabled"
value="${ user.userName }">
</div>
<div class="form-group">
<input id="register-password" class="input-material" type="password" name="passWord" placeholder="请输入密码">
<div class="invalid-feedback">
密码必须在6~10位之间
</div>
</div>
<div class="form-group">
<input id="register-passwords" class="input-material" type="password" name="confirmPassWord" placeholder="确认密码">
<div class="invalid-feedback">
两次密码必须相同 且在6~10位之间
</div>
</div>
<div class="form-group">
<button id="regbtn" type="button" name="registerSubmit" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
<script src="static/js/common-js.js"></script>
<script>
$(function() {
/*错误class form-control is-invalid
正确class form-control is-valid*/
var flagPas = false;
var flagPass = false;
var passWord, passWords;
/*验证密码*/
$("#register-password").change(function() {
passWord = $("#register-password").val();
if (passWord.length < 6 || passWord.length > 18) {
$("#register-password").removeClass("form-control is-valid")
$("#register-password").addClass("form-control is-invalid");
flagPas = false;
} else {
$("#register-password").removeClass("form-control is-invalid")
$("#register-password").addClass("form-control is-valid");
flagPas = true;
}
})
/*验证确认密码*/
$("#register-passwords").change(function() {
passWords = $("#register-passwords").val();
if ((passWord != passWords) || (passWords.length < 6 || passWords.length > 18)) {
$("#register-passwords").removeClass("form-control is-valid")
$("#register-passwords").addClass("form-control is-invalid");
flagPass = false;
} else {
$("#register-passwords").removeClass("form-control is-invalid")
$("#register-passwords").addClass("form-control is-valid");
flagPass = true;
}
})
$("#regbtn").click(function() {
if (flagPas && flagPass) {
$.ajax({
url: "${baseurl}/user/updatePassword",
type: 'PUT',
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
'passWord': passWord,
'confirmPassWord': passWords
}),
success: function(data) {
alert(data.message)
if (data.result == true) {
localStorage.removeItem("passWord");
localStorage.removeItem("check1");
localStorage.removeItem("user");
$("#register-password").val("");
$("#register-password").removeClass("is-valid");
$("#register-passwords").val("");
$("#register-passwords").removeClass("is-valid");
top.location.href = 'login';
}
}
});
} else {
if (!flagPas) {
$("#register-password").addClass("form-control is-invalid");
}
if (!flagPass) {
$("#register-passwords").addClass("form-control is-invalid");
}
}
})
})
</script>
</body>
</html>

@ -0,0 +1,200 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="base.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户信息</title>
<script type="text/javascript" src="static/js/common-css.js"></script>
<style type="text/css">
#form_content {
text-align: center;
padding: 20px 0px 20px 35%;
}
.content {
width: 100%;
padding: 20px 0px;
}
.content .form-group span {
display: inline-block;
line-height: 30px;
padding-right: 20px;
}
.content .form-group input {
width: 250px;
padding-left: 5px;
}
.content .form-group input#body-headUrl {
font-size: 10px;
border-bottom: none;
}
.btn_clar {
display: none;
}
</style>
</head>
<body>
<div id="form_content">
<div class="col-lg-6 bg-white">
<div class="form d-flex align-items-center">
<div class="content">
<div class="form-group">
<span>昵称</span> <input id="body-nickname" class="input-material" type="text" name="nickName" disabled="disabled"
value="${ user.nickName }">
<div class="invalid-feedback">昵称必须在2~10之间</div>
</div>
<div class="form-group">
<span>账号</span> <input id="body-userName" class="input-material" type="text" name="userName" disabled="disabled"
value="${ user.userName }">
</div>
<div class="form-group">
<span>邮箱</span> <input id="body-email" class="input-material" type="email" name="email" disabled="disabled"
value="${ user.email }">
<div class="invalid-feedback">邮箱不能为空</div>
<button id="verification" type="button" name="verification"
class="btn btn_clar" style="position: fixed;" >验证码</button>
<button id="already-verification" type="button" name="already-verification"
class="btn btn_clar" style="position: fixed;">已发送</button>
</div>
<div class="form-group">
<span>验证</span> <input id="body-email-verification" class="input-material" type="text" name="email-verification" disabled="disabled"
value="">
<div class="invalid-feedback">验证码不能为空</div>
</div>
<div class="form-group">
<span>头像</span> <input id="body-headUrl" class="input-material" type="file" name="headUrl" disabled="disabled"
value="${ user.headUrl }">
<div class="invalid-feedback">请选择头像文件</div>
</div>
<div class="form-group">
<button id="update" type="button" name="update" class="btn btn-primary">修改信息</button>
<button id="submit" type="button" name="submit" class="btn btn-primary btn_clar">确认修改</button>
<button id="reset"type="reset" name="reset" class="btn btn-primary btn_clar" style="margin-left: 40px">重置</button>
</div>
</div>
</div>
</div>
</div>
<script src="static/js/common-js.js"></script>
<script>
$(function() {
/*错误class form-control is-invalid
正确class form-control is-valid*/
var nickName = '${user.nickName}';
var flagNickName = nickName;
var flagHeadUrl = false;
var headUrl ;
var verificationTrueCode;
$("#body-nickname").change(function() {
nickName = $(this).val();
console.log(nickName)
if (nickName.length < 2 || nickName.length > 10) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid").css("display", "inline-block");
flagNickName = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid").css("display", "inline-block");
flagNickName = true;
}
})
$("#body-headUrl").change(function() {
headUrl = $(this).val();
if (!headUrl) {
$(this).removeClass("form-control is-valid").addClass("form-control is-invalid").css("display", "inline-block");
flagHeadUrl = false;
} else {
$(this).removeClass("form-control is-invalid").addClass("form-control is-valid").css("display", "inline-block");
flagHeadUrl = true;
}
})
$("#verification").click(function() {
var fromData = new FormData();
fromData.append('email',$("#body-email").val());
$.ajax({
url: "${baseurl}/mail/verification",
type: 'POST',
data: fromData,
contentType: false,
processData: false,
success: function(data) {
alert(data.message)
if (data.result == true) {
verificationTrueCode = data.data;
$("#verification").addClass("btn_clar");
$("#already-verification").removeClass("btn_clar");
} else {
if (data.path) {
top.location.href=data.path;
}
}
}
})
});
$("#update").click(function() {
$("#body-nickname").removeAttr("disabled", 'none');
$("#body-email").removeAttr("disabled", 'none');
$("#body-headUrl").removeAttr("disabled", 'none');
$("#body-email-verification").removeAttr("disabled",'none');
$("#submit").removeClass("btn_clar");
$("#reset").removeClass("btn_clar");
$("#verification").removeClass("btn_clar");
$(this).addClass("btn_clar");
});
$("#submit").click(function() {
var verificationCode = $('#body-email-verification').val()
if(verificationCode==verificationTrueCode){
if (flagNickName && flagHeadUrl) {
const oFiles = document.getElementById("body-headUrl").files;
var fromData = new FormData();
fromData.append('nickName', nickName);
fromData.append('headUrl', oFiles[0]);
fromData.append('email', $("#body-email").val());
$.ajax({
url: "${baseurl}/user/updateUserInfo",
type: 'POST',
data: fromData,
contentType: false,
processData: false,
success: function(data) {
alert(data.message)
if (data.result == true) {
localStorage.setItem("user", JSON.stringify(data.data));
location.href='userInfo';
window.parent.$(".dropdown-toggle img").attr('src', data.data.headUrl);
} else {
if (data.path) {
top.location.href=data.path;
}
}
}
});
} else {
if (!flagNickName) {
$("#body-nickname").addClass("form-control is-invalid").css("display", "inline-block");
}
if (!flagHeadUrl) {
$("#body-headUrl").addClass("form-control is-invalid").css("display", "inline-block");
}
}
}else {
alert("验证码错误!")
}
})
// 重置
$("#reset").click(function() {
$("input").each(function() {
$(this).removeClass("form-control is-invalid").val("");
});
$("#body-nickname").val('${user.nickName}');
$("#body-userName").val('${user.userName}');
$("#body-email").val('${user.email}');
})
})
</script>
</body>
</html>

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>个人健康信息管理</display-name>
<!--spring上下文配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring.xml</param-value>
</context-param>
<!--Web监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>crossXssFilter</filter-name>
<filter-class>top.beansprout.health.config.CrossXssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>crossXssFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--注册字符集过滤器:解决中文乱码问题 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--指定字符集 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--指定强制指定的字符集 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--注册中央处理器 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--制定SpringMVC的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/error/500.jsp</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/WEB-INF/error/401.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/WEB-INF/error/403.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/error/404.jsp</location>
</error-page>
<error-page>
<error-code>405</error-code>
<location>/WEB-INF/error/404.jsp</location>
</error-page>
</web-app>

@ -0,0 +1,128 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="WEB-INF/view/base.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>登录</title>
<script src="static/js/common-css.js"></script>
<link rel="stylesheet" href="static/css/login.css">
<script type="text/javascript">
// 防止退出登录后又页面回退带来的问题
const referer = '<%=request.getHeader("Referer")%>';
const target = '<%=request.getParameter("target")%>';
function getreferer() {
if ((!target || target == 'null') && referer && referer.indexOf("/home") != -1) {
top.location.href = 'login';
}
}
</script>
</head>
<body onload="getreferer()">
<div class="page login-page">
<div class="container d-flex align-items-center">
<div class="form-holder has-shadow">
<div class="row">
<!-- Logo & Information Panel-->
<div class="col-lg-6">
<div class="info d-flex align-items-center">
<div class="content">
<div class="logo">
<h1>欢迎登录</h1>
</div>
<p>个人健康信息管理系统</p>
</div>
</div>
</div>
<!-- Form Panel -->
<div class="col-lg-6 bg-white">
<div class="form d-flex align-items-center">
<div class="content">
<form class="form-validate" id="loginFrom">
<div class="form-group">
<input id="login-username" type="text" name="userName" required data-msg="请输入用户名" placeholder="用户名" value=""
class="input-material">
</div>
<div class="form-group">
<input id="login-password" type="password" name="passWord" required data-msg="请输入密码" placeholder="密码" class="input-material">
</div>
<button id="login" class="btn btn-primary">登录</button>
<div style="margin-top: -40px;">
<!-- <input type="checkbox" id="check1"/>&nbsp;<span>记住密码</span>
<input type="checkbox" id="check2"/>&nbsp;<span>自动登录</span> -->
<div class="custom-control custom-checkbox " style="float: right;">
<input type="checkbox" class="custom-control-input" id="check2"> <label class="custom-control-label" for="check2">自动登录</label>
</div>
<div class="custom-control custom-checkbox " style="float: right;">
<input type="checkbox" class="custom-control-input" id="check1"> <label class="custom-control-label" for="check1">记住密码&nbsp;&nbsp;</label>
</div>
</div>
</form>
<br /> <small>没有账号?</small><a href="register" class="signup">&nbsp;注册</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- JavaScript files-->
<script src="static/js/common-js.js"></script>
<script src="static/js/util/jquery.validate.min.js"></script>
<script src="static/js/login.js"></script>
<!--表单验证-->
<!-- Main File-->
<script>
$(window).load(function() {
/*判断上次是否勾选记住密码和自动登录*/
var check1s = localStorage.getItem("check1");
var check2s = sessionStorage.getItem("check2");
var oldName = localStorage.getItem("userName");
var oldPass = localStorage.getItem("passWord");
if (check1s == "true") {
$("#login-username").val(oldName);
$("#login-password").val(oldPass);
$("#check1").prop('checked', true);
} else {
$("#login-username").val('');
$("#login-password").val('');
$("#check1").prop('checked', false);
}
if (check2s == "true") {
$("#check2").prop('checked', true);
$("#loginFrom").submit();
} else {
$("#check2").prop('checked', false);
}
});
$("#loginFrom").submit(function(e) {
var userName = $("#login-username").val();
var passWord = $("#login-password").val();
$.ajax({
url: "${baseurl}/user/login",
type: 'POST',
data: {
'userName': userName,
'passWord': passWord
},
success: function(data) {
if (data.result == true) {
localStorage.setItem("user", JSON.stringify(data.data))
localStorage.setItem("userName", userName);
localStorage.setItem("passWord", passWord);
var check1 = $("#check1").prop('checked');
var check2 = $('#check2').prop('checked');
localStorage.setItem("check1", check1);
sessionStorage.setItem("check2", check2);
window.location.href = 'home';
} else {
alert(data.message)
}
}
});
return false;
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,120 @@
/*
* ==========================================================
* LOGIN PAGE
* ==========================================================
*/
.login-page {
position: relative;
}
.login-page::before {
content: '';
width: 100%;
height: 100%;
display: block;
z-index: -1;
background: url(../imgs/login.jpg);
background-size: cover;
-webkit-filter: blur(10px);
filter: blur(10px);
z-index: 1;
position: absolute;
top: 0;
right: 0;
}
.login-page .container {
min-height: 100vh;
z-index: 999;
padding: 20px;
position: relative;
}
.login-page .form-holder {
width: 100%;
border-radius: 5px;
overflow: hidden;
margin-bottom: 50px;
}
.login-page .form-holder .info,
.login-page .form-holder .form {
min-height: 70vh;
padding: 40px;
height: 100%;
}
.login-page .form-holder div[class*='col-'] {
padding: 0;
}
.login-page .form-holder .info {
background: rgba(121, 106, 238, 0.9);
color: #fff;
}
.login-page .form-holder .info h1 {
font-size: 2.5em;
font-weight: 600;
}
.login-page .form-holder .info p {
font-weight: 300;
}
.login-page .form-holder .form .form-group {
position: relative;
margin-bottom: 30px;
}
.login-page .form-holder .form .content {
width: 100%;
}
.login-page .form-holder .form form {
width: 100%;
max-width: 400px;
}
.login-page .form-holder .form #login,
.login-page .form-holder .form #register {
margin-bottom: 20px;
cursor: pointer;
}
.login-page .form-holder .form a.forgot-pass,
.login-page .form-holder .form a.signup {
font-size: 0.9em;
color: #85b4f2;
}
.login-page .form-holder .form small {
color: #aaa;
}
.login-page .form-holder .form .terms-conditions label {
cursor: pointer;
color: #aaa;
font-size: 0.9em;
}
.login-page .copyrights {
width: 100%;
z-index: 9999;
position: absolute;
bottom: 0;
left: 0;
color: #fff;
}
@media (max-width: 991px) {
.login-page .info,
.login-page .form {
min-height: auto !important;
}
.login-page .info {
padding-top: 100px !important;
padding-bottom: 100px !important;
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1,13 @@
/* 移动端设置 */
document.write('<meta charset="UTF-8">');
document.write('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">');
document.write('<meta http-equiv="X-UA-Compatible" content="IE=edge">');
/* 移动端兼容 */
document.write('<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">');
/* 搜索引擎优化 */
document.write('<meta name="description" content="个人健康信息管理">');
document.write('<meta name="robots" content="all,follow">');
document.write('<link type="text/css" rel="stylesheet" href="static/css/base.css" />');
/* 最新版本的 Bootstrap 核心 CSS 文件 */
document.write('<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/4.2.1/css/bootstrap.min.css">');

@ -0,0 +1,43 @@
/* bootstrap */
document.write('<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>');
document.write('<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>');
document.write('<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>');
// input浮点数处理
function clearNoNum(obj){
obj.value = obj.value.replace(/[^\d.]/g,""); //清除“数字”和“.”以外的字符
obj.value = obj.value.replace(/\.{2,}/g,"."); //只保留第一个. 清除多余的
obj.value = obj.value.replace(".","$#$").replace(/\./g,"").replace("$#$",".");
obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d).*$/,'$1$2.$3');//只能输入两个小数
//如果没有小数点,不能为类似 01、02的金额
if(obj.value.indexOf(".")< 0 && obj.value !=""){
obj.value= parseFloat(obj.value);
}
//如果有小数点,不能为类似 1.10的金额
if(obj.value.indexOf(".")> 0 && obj.value.indexOf("0")>2){
obj.value= parseFloat(obj.value);
}
//如果有小数点,不能为类似 0.00的金额
if(obj.value.indexOf(".")> 0 && obj.value.lastIndexOf("0")>1){
obj.value= parseFloat(obj.value);
}
}
function dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}

@ -0,0 +1,175 @@
$(document).ready(function () {
'use strict';
// ------------------------------------------------------- //
// Search Box
// ------------------------------------------------------ //
$('#search').on('click', function (e) {
e.preventDefault();
$('.search-box').fadeIn();
});
$('.dismiss').on('click', function () {
$('.search-box').fadeOut();
});
// ------------------------------------------------------- //
// Card Close
// ------------------------------------------------------ //
$('.card-close a.remove').on('click', function (e) {
e.preventDefault();
$(this).parents('.card').fadeOut();
});
// ------------------------------------------------------- //
// Tooltips init
// ------------------------------------------------------ //
$('[data-toggle="tooltip"]').tooltip()
// ------------------------------------------------------- //
// Adding fade effect to dropdowns
// ------------------------------------------------------ //
$('.dropdown').on('show.bs.dropdown', function () {
$(this).find('.dropdown-menu').first().stop(true, true).fadeIn();
});
$('.dropdown').on('hide.bs.dropdown', function () {
$(this).find('.dropdown-menu').first().stop(true, true).fadeOut();
});
// ------------------------------------------------------- //
// Sidebar Functionality
// ------------------------------------------------------ //
$('#toggle-btn').on('click', function (e) {
e.preventDefault();
$(this).toggleClass('active');
$('.side-navbar').toggleClass('shrinked');
$('.content-inner').toggleClass('active');
$(document).trigger('sidebarChanged');
if ($(window).outerWidth() > 1183) {
if ($('#toggle-btn').hasClass('active')) {
$('.navbar-header .brand-small').hide();
$('.navbar-header .brand-big').show();
} else {
$('.navbar-header .brand-small').show();
$('.navbar-header .brand-big').hide();
}
}
if ($(window).outerWidth() < 1183) {
$('.navbar-header .brand-small').show();
}
});
// ------------------------------------------------------- //
// Universal Form Validation
// ------------------------------------------------------ //
$('.form-validate').each(function() {
$(this).validate({
errorElement: "div",
errorClass: 'is-invalid',
validClass: 'is-valid',
ignore: ':hidden:not(.summernote, .checkbox-template, .form-control-custom),.note-editable.card-block',
errorPlacement: function (error, element) {
// Add the `invalid-feedback` class to the error element
error.addClass("invalid-feedback");
if (element.prop("type") === "checkbox") {
error.insertAfter(element.siblings("label"));
}
else {
error.insertAfter(element);
}
}
});
});
// ------------------------------------------------------- //
// Material Inputs
// ------------------------------------------------------ //
var materialInputs = $('input.input-material');
// activate labels for prefilled values
materialInputs.filter(function() { return $(this).val() !== ""; }).siblings('.label-material').addClass('active');
// move label on focus
materialInputs.on('focus', function () {
$(this).siblings('.label-material').addClass('active');
});
// remove/keep label on blur
materialInputs.on('blur', function () {
$(this).siblings('.label-material').removeClass('active');
if ($(this).val() !== '') {
$(this).siblings('.label-material').addClass('active');
} else {
$(this).siblings('.label-material').removeClass('active');
}
});
// ------------------------------------------------------- //
// Footer
// ------------------------------------------------------ //
var contentInner = $('.content-inner');
$(document).on('sidebarChanged', function () {
adjustFooter();
});
$(window).on('resize', function () {
adjustFooter();
})
function adjustFooter() {
var footerBlockHeight = $('.main-footer').outerHeight();
contentInner.css('padding-bottom', footerBlockHeight + 'px');
}
// ------------------------------------------------------- //
// External links to new window
// ------------------------------------------------------ //
$('.external').on('click', function (e) {
e.preventDefault();
window.open($(this).attr("href"));
});
// ------------------------------------------------------ //
// For demo purposes, can be deleted
// ------------------------------------------------------ //
var stylesheet = $('link#theme-stylesheet');
$("<link id='new-stylesheet' rel='stylesheet'>").insertAfter(stylesheet);
var alternateColour = $('link#new-stylesheet');
if ($.cookie("theme_csspath")) {
alternateColour.attr("href", $.cookie("theme_csspath"));
}
$("#colour").change(function () {
if ($(this).val() !== '') {
var theme_csspath = 'css/style.' + $(this).val() + '.css';
alternateColour.attr("href", theme_csspath);
$.cookie("theme_csspath", theme_csspath, {
expires: 365,
path: document.URL.substr(0, document.URL.lastIndexOf('/'))
});
}
return false;
});
});

File diff suppressed because one or more lines are too long

@ -0,0 +1,16 @@
/**
* Simplified Chinese translation for bootstrap-datetimepicker
* Yuan Cheung <advanimal@gmail.com>
*/
;(function($){
$.fn.datetimepicker.dates['zh-CN'] = {
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
today: "今天",
suffix: [],
meridiem: ["上午", "下午"]
};
}(jQuery));

File diff suppressed because one or more lines are too long

@ -0,0 +1,10 @@
#版本1.0.0为gitee开源版本修改了数据库为本地数据库之后的版本
功能:每日健康打开、历史打卡记录、健康周报、登陆注册、头像上传、修改资料和修改密码等。
#版本1.0.1修复了时间组件显示乱码问题
#版本1.0.2修复了头像未上传成功的问题
#版本2.0.2增加了默认头像,增加了邮箱认证功能,增加了近期推送功能
#版本2.0.3修复了近期推送邮箱未绑定没有提示的问题
Loading…
Cancel
Save