需要安装以下软件:
如果开发一些软件,java,需要哪些必须的软件?
0. JDK11
1. IDEA--->IDE
2. 数据库管理系统软件 MySQL8.0+
3. Navicat
4. Axure Vscode
5. typora----> md文件
6. Git---> Gitee 码云 Github
前后端分离方式
前端:
html
css
js(重点) es6语法
Vue(指令)+组件(暂且不用)+Axios 交互
后端:
SpringBoot2(Spring+SpringMVC) +Mybatis3.*+其它
注解开发
使用VScode创建前端项目:
1. 创建前端页面
创建springboot:
1. 使用idea创建maven工程
2. 使用项目引导器
maven: 项目构建工具
1.管理依赖(jar)
1.1 本机有本地仓库
1.2 从配置的云仓库下载
2.创建聚合工程
<?xml version="1.0" encoding="UTF-8"?>
<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>com.by.medical</groupId>
<artifactId>zhenggong-medical-system</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--引入项目需要的依赖-->
<!--1.引入父级项目依赖-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.6.4</version>
</parent>
<!--2.引入web-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
server:
port: 9000
@SpringBootApplication
public class MedicalApplication {//启动类----> 运行run
public static void main(String[] args) {
SpringApplication.run(MedicalApplication.class,args);
}
}
在浏览器/postman发起请求测试 http://127.0.0.1:9000/hello
@RestController
public class HelloController {
@GetMapping("/hello")
public Map hello(){
return Map.of("name","炭治郎");
}
}
集成数据库
1.1 在pom.xml文件中 引入mybatis相关的依赖
1.mybatis
2.mysql的驱动
3.数据库连接池(druid)
4.lombok
<?xml version="1.0" encoding="UTF-8"?>
<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>com.by.medical</groupId>
<artifactId>zhenggong-medical-system</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--引入项目需要的依赖-->
<!--1.引入父级项目依赖-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.6.4</version>
</parent>
<dependencies>
<!--2.引入web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--3.引入mybatis相关依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
1.2 在application.yml文件中,配置连接数据库相关的信息
server:
port: 9000
#配置数据库相关
spring:
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/medical
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
initial-size: 10
max-active: 20
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package: com.by.medical.mapper
1.3 修改项目核心配置 加载mapper
@SpringBootApplication
@MapperScan("com.by.medical.mapper")
public class MedicalApplication {//启动类----> 运行run
public static void main(String[] args) {
SpringApplication.run(MedicalApplication.class,args);
}
}
@Data
public class SysUser implements java.io.Serializable{
private Integer id;
private String userTrueName;
private String password;
private String jobNumber;
private Integer gender;
private String phone;
private String email;
private String wechat;
private String qqNumber;
private String userImage;
private String address;
private Integer deptId;
private Integer jobId;
private Integer regionId;
private Integer provinceId;
private Integer groupId;
private Integer productGroupId;
private java.time.LocalDateTime createTime;
private java.time.LocalDateTime updateTime;
}
在项目中 新建mapper包
@Mapper
public interface SysUserMapper {
List<SysUser> queryAll();
}
在项目的resources目录下,创建mapper目录,将mapper映射文件存储在mapper目录下
<?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="com.by.medical.mapper.SysUserMapper">
<select id="queryAll" resultType="com.by.medical.bean.SysUser">
SELECT * FROM sys_user
</select>
</mapper>
server:
port: 9000
#配置数据库相关
spring:
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/medical
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
initial-size: 10
max-active: 20
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package: com.by.medical.bean
mapper-locations: mapper/*.xml
- 创建数据库
- 创建表
CREATE TABLE `sys_user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '用户id,自增',
`user_true_name` varchar(255) DEFAULT NULL COMMENT '用户真实姓名',
`password` varchar(255) DEFAULT NULL COMMENT '用户密码 初始化密码123456',
`job_number` varchar(255) DEFAULT NULL COMMENT '用户工号',
`gender` tinyint(1) DEFAULT '0' COMMENT '用户性别 0 男 1 女 默认男',
`phone` varchar(255) DEFAULT NULL COMMENT '用户手机号码',
`email` varchar(255) DEFAULT NULL COMMENT '邮箱',
`wechat` varchar(255) DEFAULT NULL COMMENT '微信号',
`qq_number` varchar(255) DEFAULT NULL COMMENT 'qq号',
`user_image` varchar(255) DEFAULT NULL COMMENT '用户头像',
`address` varchar(255) DEFAULT NULL COMMENT '联系地址',
`dept_id` int DEFAULT NULL COMMENT '部门id',
`job_id` int DEFAULT NULL COMMENT '职位id',
`region_id` int DEFAULT NULL COMMENT '大区id',
`province_id` int DEFAULT NULL COMMENT '地区id',
`group_id` int DEFAULT NULL COMMENT '组id',
`product_group_id` int DEFAULT NULL COMMENT '产品组id',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '新增时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
分析:
根据手机号+密码,工号+密码
<form id="loginForm">
<div class="dataform">
<div class="input-warp gap">
<span class="input-icon iconfont icon-yonghu1"></span>
<input id="userName" type="text" class="inputs" placeholder="请输入手机号/工号" maxlength="64"
v-model="phoneOrNo">
</div>
<div class="input-warp gap">
<span class="input-icon iconfont icon-baomi"></span>
<input class="inputs" type="password" placeholder="请输入密码" id="password" maxlength="20"
v-model="pass">
</div>
<div class="btn-warp gap">
<div class="text-center">
<button id="btnLogin" type="button" class="btn btn-block lgbtn blue"
@click="userLogin">登录</button>
</div>
</div>
<div class="gap">
<div class="pull-right" style="margin-top: 6px">
<a href="javascript:;" class="link">忘记密码?</a>
<!-- <span class="split-space">|</span>
<a href="/page/user/register.html" class="link">新用户注册</a> -->
</div>
</div>
<!-- <div class="biggap third-party-title">
<h5 class="text-center"><span>第三方账号登录</span></h5>
</div> -->
<!-- <div class="third-auth">
<a title="用钉钉登录" class="dt" href="javascript:;"></a>
<a title="用微信账户登录" class="wx" href="javascript:;"></a>
<a title="用QQ账户登录" class="qq" href="javascript:;"></a>
</div> -->
</div>
</form>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.10/vue.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
<script>
// vue+axios
//1.引入vue.js axios.js
//2.获得用户登录的手机号/工号和密码
//3.发起异步请求(把数据提交到后端)
let vue = new Vue({
el: "#main",
data: {
phoneOrNo: "",
pass: "",
errorMsg:"",
},
methods: {
userLogin() {
//发起异步请求
//axios.get(`请求路径`,`参数`);
axios.get(`http://127.0.0.1:9000/api/user/login?phoneOrNo=` + this.phoneOrNo + `&pass=` + this.pass)
.then(response => {
//response就是服务器响应的数据
//console.log("成功的回调结果:");
//console.log(response.data);
let {status,msg,data} = response.data;
if(status=="200"){
//登录成功
//页面跳转
location.replace("http://www.baidu.com");
}else{
this.errorMsg = msg;
this.phoneOrNo = "";
this.pass = "";
}
}).catch(error => {
console.log(error);
});
}
},
});
</script>
@GetMapping("/login")
public AxiosResult<SysUser> userLogin(@RequestParam("phoneOrNo") String phoneOrNo, @RequestParam("pass") String pass){
//String phoneOrNo,String pass 是前端提交数据
SysUser sysUser = sysUserMapper.userLogin(phoneOrNo,pass);
if(sysUser==null){
return AxiosResult.error(StatusEnum.USER_LOGIN_ERROR);
}
return AxiosResult.success(sysUser);
}
@Mapper
public interface SysUserMapper {
List<SysUser> queryAll();
SysUser userLogin(@Param("phoneOrNo") String phoneOrNo, @Param("pass") String pass);
}
修改SysUserMapper.xml内容
<select id="userLogin" resultType="com.by.medical.bean.SysUser">
SELECT * FROM sys_user
WHERE
(`password`= #{pass} AND job_number= #{phoneOrNo})
OR
(phone=#{phoneOrNo} AND `password`=#{pass});
</select>
用户登录成功之后,应该要跳转到首页
1.创建index.html ok
2.在首页上,展示个人部分信息(用户真实名称,用户头像)
3.核心: 在index.html中获得并展示用户信息?
3.1 获得 登录成功之后 服务器响应完整的用户对象信息
3.2 困难点 把login.html内容传到index.html
解决方案:
1. 在跳转的时候 拼接想要的数据 在index.html 使用URLSearchParams
let { userTrueName, userImage } = data;
//页面跳转
location.replace("/medical-page/page/index.html?name="
+ encodeURIComponent(userTrueName)
+ "&image=" + encodeURIComponent(userImage));
2. 在index.html获得页面跳转并携带的数据
2.1 在index.html 引入vue.js axios.js
2.2 利用vue的生命周期中钩子函数 获得数据
<script>
let vue = new Vue({
el: "#container",
data: {
userImage:"",
userName:"",
},
created() {
//获得登录页面跳转到首页携带的数据
let params = new URLSearchParams(window.location.search);
this.userName = params.get("loginName");
this.userImage = "http://127.0.0.1:9000"+params.get("image");
},
});
</script>
//浏览器缓存:
//localStorage----> 永远都不会丢失 除非自动删除
//sessionStorage----> session会话 session过期 关闭浏览器
在login.html里面
//2.第二种方式 将数据存储缓存 localStorage
let {userTrueName, userImage,id } = data;
//将数据转换成json数据字符串存储
let userObj = {name:userTrueName,image:userImage,id:id};
localStorage.setItem("loginUserInfo",JSON.stringify(userObj));
location.replace("/medical-page/page/index.html");
在index.html中
<script>
let vue = new Vue({
el: "#container",
data: {
userImage:"",
userName:"",
},
created() {
//获得登录页面跳转到首页携带的数据
//1.第一种方式获得
// let params = new URLSearchParams(window.location.search);
// this.userName = params.get("loginName");
// this.userImage = "http://127.0.0.1:9000"+params.get("image");
//2.使用缓存技术
let loginUserInfoStr = localStorage.getItem("loginUserInfo");
//json字符串转换成对象
let userObj = JSON.parse(loginUserInfoStr);
this.userName = userObj.name;
this.userImage = "http://127.0.0.1:9000"+userObj.image;
},
});
</script>
//2.第二种方式 将数据存储缓存 localStorage
let {userTrueName, userImage,id } = data;
//将数据转换成json数据字符串存储
let userObj = {name:userTrueName,image:userImage,id:id};
localStorage.setItem("loginUserInfo",JSON.stringify(userObj));
location.replace("/medical-page/page/index.html");
- 创建用户列表页面 medical-page/page/user/list.html
- 从缓存localStorage获得存储的用户信息(真实名称,用户头像)
- 查询用户信息
- 查询单表(sys_user)是不对的,数据不完整。
//发现在信息展示里面,用户信息中,要展示用户所在的部门名称,用户职位
CREATE TABLE `dept` (
`id` int NOT NULL AUTO_INCREMENT,
`dept_name` varchar(255) DEFAULT NULL,
`dept_loc` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `job_info` (
`id` int NOT NULL AUTO_INCREMENT,
`job_name` varchar(255) DEFAULT NULL COMMENT '职务名称 角色',
`job_desc` varchar(255) DEFAULT NULL COMMENT '职务描述',
`job_status` tinyint(1) DEFAULT '1' COMMENT '0 false 1 true',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 查询用户信息,并展示用户所在的部门名称,与职位名称
SELECT
u.*,d.dept_name,j.job_name
FROM
sys_user AS u,dept AS d,job_info AS j
WHERE
u.dept_id=d.id AND u.job_id=j.id;
//mapper返回是xxxDTO
//service里面将DTO转换成VO
@Data
public class SysUserVO implements Serializable {
private Integer id;
private String userTrueName;
private String password;
private String jobNumber;
private Integer gender;
private String phone;
private String email;
private String wechat;
private String qqNumber;
private String userImage;
private String address;
private Integer deptId;
private Integer jobId;
private Integer regionId;
private Integer provinceId;
private Integer groupId;
private Integer productGroupId;
private java.time.LocalDateTime createTime;
private java.time.LocalDateTime updateTime;
private String deptName;
private String jobName;
}
//查询用户信息,查询部门名称+职位名称
@GetMapping("/query")
public AxiosResult<List<SysUserVO>> queryUserAndDeptAndJob(){
return AxiosResult.success(sysUserMapper.queryUserAndDeptAndJob());
}
@Mapper
public interface SysUserMapper {
List<SysUser> queryAll();
SysUser userLogin(@Param("phoneOrNo") String phoneOrNo, @Param("pass") String pass);
List<SysUserVO> queryUserAndDeptAndJob();
}
<select id="queryUserAndDeptAndJob" resultType="com.by.medical.vo.SysUserVO">
SELECT
u.*,d.dept_name,j.job_name
FROM
sys_user AS u,dept AS d,job_info AS j
WHERE
u.dept_id=d.id AND u.job_id=j.id
</select>
<script>
let vue = new Vue({
el: "#container",
data: {
trueName: "",
userImage: "",
userList: {},
},
methods: {
queryAllUserInfo() {
//查询数据库的所有的用户信息 展示list.html
//异步查询
axios.get(`http://127.0.0.1:9000/api/user/query`)
.then(response => {
let { status, msg, data } = response.data;
this.userList = data;
});
},
},
created() {
let infoStr = localStorage.getItem("loginUserInfo");
let userObj = JSON.parse(infoStr);
this.trueName = userObj.name;
this.userImage = "http://127.0.0.1:9000" + userObj.image;
//查询所有用户信息
this.queryAllUserInfo();
},
});
</script>
<tbody>
<tr v-for="(user,index) in userList" :key="index">
<td>
<input type="checkbox" name="" id=" ">
</td>
<td>{{user.jobNumber}}</td>
<td class="hidden-phone">{{user.userTrueName}}</td>
<td>{{user.phone}}</td>
<td><span class="label label-info label-mini">{{user.deptName}}</span></td>
<td><span class="label label-success label-mini">{{user.jobName}}</span></td>
<td>{{user.createTime}}</td>
<td>
<button class="btn btn-success btn-xs" data-toggle="modal"
data-target="#myModal">
<i class="fa fa-check">用户详情</i>
</button>
<button class="btn btn-primary btn-xs" data-toggle="modal"
data-target="#editModal">
<i class="fa fa-pencil">编辑</i>
</button>
<button class="btn btn-danger btn-xs">
<i class="fa fa-trash-o ">删除</i>
</button>
<button class="btn btn-warning btn-xs">
<i class="fa fa-pencil ">修改密码</i>
</button>
</td>
</tr>
</tbody>
1. 修改list.html页面 创建新增用户模态框
2. 用户录入数据-----> 获得用户动态录入的所有的数据----->vue v-model insertUserObj
3. 发起异步请求-----> 持久化保存数据库-----> 编写insert 存储到sys_user
4. 操作dept,job_info 完成查询所有部门+职位
SELECT * FROM dept
实体类
@Data
public class Dept implements Serializable {
private Integer id;
private String deptName;
private String deptLoc;
}
controller
@RestController
@RequestMapping("/api/dept/")
public class DeptController {
@Autowired
private DeptMapper deptMapper;
//查询所有部门
@GetMapping("/query")
public AxiosResult<List<Dept>> queryAllDept(){
return AxiosResult.success(deptMapper.queryAllDept());
}
}
mapper接口
@Mapper
public interface DeptMapper {
List<Dept> queryAllDept();
}
mapper映射文件
<?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="com.by.medical.mapper.DeptMapper">
<select id="queryAllDept" resultType="dept">
SELECT * FROM dept
</select>
</mapper>
select * from job_info;
@Data
public class JobInfo implements Serializable {
private Integer id;
private String jobName;
private String jobDesc;
private Boolean jobStatus;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
@RestController
@RequestMapping("/api/job/")
public class JobInfoController {
@Autowired
private JobInfoMapper jobInfoMapper;
@GetMapping("/query")
public AxiosResult<List<JobInfo>> queryAllJobInfo(){
return AxiosResult.success(jobInfoMapper.queryAllJobInfo());
}
}
@Mapper
public interface JobInfoMapper {
List<JobInfo> queryAllJobInfo();
}
<mapper namespace="com.by.medical.mapper.JobInfoMapper">
<select id="queryAllJobInfo" resultType="com.by.medical.bean.JobInfo">
select * from job_info
</select>
</mapper>
在页面上展示所有部门,所有职位信息。
1.新增点击事件 2.编写js函数
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-6">
<select class="form-control m-b" name="account"
@click="queryAllDept">
<option selected>请选择</option>
<option v-for="(dept,index) in deptList" :key="index" :value="dept.id"
>{{dept.deptName}}</option>
</select>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label">职位</label>
<div class="col-sm-6">
<select class="form-control m-b" name="account"
@click="queryAllJobInfo">
<option>请选择</option>
<option v-for="(job,index) in jobList" :key="index" :value="job.id">{{job.jobName}}</option>
</select>
</div>
</div>
<script>
let vue = new Vue({
el: "#container",
data: {
trueName: "",
userImage: "",
userList: {},
deptList:{},
jobList:{},
},
methods: {
queryAllUserInfo() {
//查询数据库的所有的用户信息 展示list.html
//异步查询
axios.get(`http://127.0.0.1:9000/api/user/query`)
.then(response => {
let { status, msg, data } = response.data;
this.userList = data;
});
},
queryAllDept(){
axios.get(`http://127.0.0.1:9000/api/dept/query`).then(response=>{
let {status,msg,data} = response.data;
if(status=="200"){
this.deptList = data;
}
});
},
queryAllJobInfo(){
axios.get(`http://127.0.0.1:9000/api/job/query`).then(response=>{
let {status,msg,data} = response.data;
if(status=="200"){
this.jobList = data;
}
});
}
},
created() {
let infoStr = localStorage.getItem("loginUserInfo");
let userObj = JSON.parse(infoStr);
this.trueName = userObj.name;
this.userImage = "http://127.0.0.1:9000" + userObj.image;
//查询所有用户信息
this.queryAllUserInfo();
},
});
</script>
<div id="modal-form" class="modal fade" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body" style="margin-left: 30px;">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5 style="font-weight: bolder;">新增用户</h5>
<button type="button" class="close" data-dismiss="modal"
style="margin-top: -30px;" aria-hidden="true">×</button>
</div>
<br>
<div class="ibox-content">
<form method="get" class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">姓名:</label>
<div class="col-sm-6">
<input type="text" v-model="insertUserObj.userTrueName" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label">密码:</label>
<div class="col-sm-6">
<input type="text" v-model="insertUserObj.password" disabled value="123456"
class="form-control">(系统生成初始密码)
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">工号</label>
<div class="col-sm-6">
<input type="text" v-model="insertUserObj.jobNumber" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label">性别<br />
</label>
<div class="col-sm-10">
<div class="radio-inline">
<label>
<input type="radio" checked="" value="0"
v-model="insertUserObj.gender"
name="gender">男
</label>
</div>
<div class="radio-inline">
<label>
<input type="radio" value="1" v-model="insertUserObj.gender"
name="gender">女
</label>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">联系方式</label>
<div class="col-sm-6">
<input type="text" v-model="insertUserObj.phone" class="form-control"></div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-lg-2 control-label">Email</label>
<div class="col-lg-6">
<input type="text" v-model="insertUserObj.email" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-lg-2 control-label">微信账号</label>
<div class="col-lg-6">
<input type="text" v-model="insertUserObj.wechat" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-lg-2 control-label">QQ账号</label>
<div class="col-lg-6">
<input type="text" v-model="insertUserObj.qqNumber" class="form-control">
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label">部门</label>
<div class="col-sm-6">
<select class="form-control m-b" name="account"
@click="queryAllDept" v-model="insertUserObj.deptId">
<option value="-1">请选择</option>
<option v-for="(dept,index) in deptList" :key="index" :value="dept.id"
>{{dept.deptName}}</option>
</select>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label class="col-sm-2 control-label">职位</label>
<div class="col-sm-6">
<select class="form-control m-b" name="account"
@click="queryAllJobInfo" v-model="insertUserObj.jobId">
<option value="-1">请选择</option>
<option v-for="(job,index) in jobList" :key="index" :value="job.id">{{job.jobName}}</option>
</select>
</div>
</div>
<div class="form-group"><label class="col-sm-2 control-label">联系地址</label>
<div class="col-sm-6">
<input type="text" v-model="insertUserObj.address" class="form-control" >
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-danger" type="reset">重置</button>
<button class="btn btn-primary" @click="insertUser" type="button">提交</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
insertUser(){
//获得用户录入的信息
//异步调用
axios.post(`http://127.0.0.1:9000/api/user/insert`,this.insertUserObj)
.then(response=>{
location.replace("/medical-page/page/user/list.html");
});
}
},
//新增用户
@PostMapping("/insert")
public AxiosResult<?> insertUser(@RequestBody SysUser sysUser){
//System.out.println("获得新增用户信息:"+sysUser);
sysUserMapper.insertUser(sysUser);
return AxiosResult.success();
}
@Mapper
public interface SysUserMapper {
void insertUser(SysUser sysUser);
}
<insert id="insertUser">
INSERT INTO sys_user
(user_true_name, `password`, job_number, gender, phone, email, wechat, qq_number, address, dept_id, job_id)
VALUES
(#{userTrueName},#{password},#{jobNumber},#{gender},#{phone},#{email},#{wechat},#{qqNumber},#{address},#{deptId},#{jobId})
</insert>
查询单个用户信息。
1.在list.html页面中,找到"用户详情"按钮,新增事件。click
2.在vue实例中,创建新的函数queryUserById(uid)
3.编写sql
SELECT
u.*,d.dept_name,j.job_name
FROM
sys_user AS u,dept AS d,job_info AS j
WHERE
u.id = #{id} AND u.dept_id=d.id AND u.job_id=j.id;
controller
//查询单个用户
//http://127.0.0.1:9000/api/user/query/13
@GetMapping("/query/{uid}")
public AxiosResult<SysUserVO> queryUserById(@PathVariable int uid){
return AxiosResult.success(sysUserMapper.queryById(uid));
}
mapper接口
SysUserVO queryById(int uid);
mapper映射
<select id="queryById" resultType="com.by.medical.vo.SysUserVO">
SELECT
u.*,d.dept_name,j.job_name
FROM
sys_user AS u,dept AS d,job_info AS j
WHERE
u.id = #{id} AND u.dept_id=d.id AND u.job_id=j.id;
</select>
html
<div class="modal-body">
<div class="ibox-content">
<div style="font-size: 15px;">
<div style="margin-top: 80px;position: fixed;">
<img :src="queyUserObj.userImage" alt="" style="width: 100px; height: 100px; text-align: center;">
</div>
<div style="position:relative; margin-left: 180px;">
姓名: {{queyUserObj.userTrueName}} <br>
工号: {{queyUserObj.jobNumber}} <br>
性别: {{queyUserObj.gender==0?'男':'女'}} <br>
<br>
联系方式: {{queyUserObj.phone}} <br>
邮箱: {{queyUserObj.email}} <br>
微信账号: {{queyUserObj.wechat}} <br>
<br>
QQ号: {{queyUserObj.qqNumber}} <br>
部门: {{queyUserObj.deptName}} <br>
职位: {{queyUserObj.jobName}} <br>
<br>
联系地址: {{queyUserObj.address}} <br>
</div>
</div>
</div>
</div>
MySQL数据库中,有哪些约束自带索引?
1.1 主键约束
1.2 外键约束
1.3 唯一性约束
index: 本质是就是数据结构。建议创建index。 提高查询的性能。Btree
分析:
修改个人信息。
查看个人原来信息的前提下,进行修改。设置新的数据。
update
在开发中,执行修改,删除,前提都要查询。
1.修改与新增共用1个模态框
2.在修改按钮上,新增一个click事件,调用编写过的queryUserById(id)
3.会影响新增功能,在新增按钮上新增一个点击事件,addBtn 清除insertUserObj对象里面的数据
4.需要在页面:
<input type="hidden" v-model="insertUserObj.id">
5.在后端代码里面 根据用户是否提交id 判断 执行新增? 修改?
<update id="updateUser">
update sys_user
set user_true_name=#{userTrueName},
`password`=#{password},
job_number=#{jobNumber},
gender=#{gender},
phone=#{phone},
email=#{email},
wechat=#{wechat},
qq_number=#{qqNumber},
address=#{address},
dept_id=#{deptId},
job_id=#{jobId}
where id = #{id}
</update>
//新增/修改用户
@PostMapping("/insertOrUpdate")
public AxiosResult<?> insertUser(@RequestBody SysUser sysUser){
Integer id = sysUser.getId();
if(id==null){
sysUserMapper.insertUser(sysUser);
}else{
//执行修改
sysUserMapper.updateUser(sysUser);
}
return AxiosResult.success();
}
void updateUser(SysUser sysUser);
根据id删除。(id 主键列 自带索引 根据id操作数据 比根据普通列操作 性能高)
下午作业:
实现删除用户功能。
实现方式:
方式1.可以纯前端实现(js实现)----->不要编写后端代码
1.1 编写table标签,编写js实现删除一行内容
方式2.可以纯后端代码实现(编写后端接口)
2.1 编写后端代码,删除数据库1行记录
方式3. 前后端开发(既写前端页面,又写后端代码)
deleteUserById(uid) {
if (window.confirm("确认要删除吗?" + uid)) {
//发起异步请求 调用后端接口 删除数据库数据
axios.delete(`http://127.0.0.1:9000/api/user/delete/` + uid)
.then(response => {
//页面继续跳转list.html
location.replace = "/medical-page/page/user/list.html";
});
}
},
//根据id删除用户
@DeleteMapping("/delete/{uid}")
public AxiosResult<?> deleteById(@PathVariable int uid){
sysUserMapper.deleteUserById(uid);
return AxiosResult.success();
}
void deleteUserById(int uid);
<delete id="deleteUserById">
DELETE FROM sys_user WHERE id=#{id}
</delete>
问题: 不能删除当前登录者
deleteUserById(uid) {
//判断删除的用户是否是登录者
//是 不能删除
//如何判断呢? 登录成功之后 localstorage
//从缓存里面获得用户id
let loginUserInfoStr = localStorage.getItem("loginUserInfo");
let loginUserObj = JSON.parse(loginUserInfoStr);
let loginUserId = loginUserObj.id;
if(uid==loginUserId){
alert("无法删除用户");
return;
}
if (window.confirm("确认要删除吗?" + uid)) {
//发起异步请求 调用后端接口 删除数据库数据
axios.delete(`http://127.0.0.1:9000/api/user/delete/` + uid)
.then(response => {
//页面继续跳转list.html
location.replace("/medical-page/page/user/list.html");
});
}
},
deleteUserBatch(){
//1.获得用户选择要删除的多行记录id---->获得多个id
//===> 获得多个复选框的value属性的数据
let idArary = [];
let checkboxArray = document.querySelectorAll(".myCheckBox");
checkboxArray.forEach(checkBox=>{
if(checkBox.checked){
idArary.push(checkBox.value);
}
});
let flag = false;
idArary.forEach(id=>{
if(id==this.loginUserId){
flag = true;
}
});
if(flag){
alert("无法删除登录者的信息");
return;
}
//可以删除
idArary.forEach(uid=>{
axios.delete(`http://127.0.0.1:9000/api/user/delete/` + uid);
});
location.replace("/medical-page/page/user/list.html");
},
分页查询用户信息
每页展示5条记录。
SELECT u.*,
d.dept_name,
j.job_name
FROM sys_user AS u,
dept AS d,
job_info AS j
WHERE u.dept_id = d.id
AND u.job_id = j.id
ORDER BY u.id DESC
LIMIT (page-1)*size,size
1.在页面上手动引入zpageNav.js
2.在页面引入分页标签
<script>
let vue = new Vue({
el: "#container",
data: {
trueName: "",
userImage: "",
userList: {},
deptList: {},
jobList: {},
insertUserObj: {},
queyUserObj: {},
loginUserId: 0,
//分页相关的数据
page: 1, //显示的是哪一页
pageSize: 5, //每一页显示的数据条数
total: 30, //记录总数
maxPage: 6, //最大页数
},
methods: {
//pagehandler方法 跳转到page页
pageHandler(page) {
this.page = page;
//发起异步请求 分页查询用户信息
this.queryAllUserInfo();
},
deleteUserBatch() {
//1.获得用户选择要删除的多行记录id---->获得多个id
//===> 获得多个复选框的value属性的数据
let idArary = [];
let checkboxArray = document.querySelectorAll(".myCheckBox");
checkboxArray.forEach(checkBox => {
if (checkBox.checked) {
idArary.push(checkBox.value);
}
});
let flag = false;
idArary.forEach(id => {
if (id == this.loginUserId) {
flag = true;
}
});
if (flag) {
alert("无法删除登录者的信息");
return;
}
//可以删除
idArary.forEach(uid => {
axios.delete(`http://127.0.0.1:9000/api/user/delete/` + uid);
});
location.replace("/medical-page/page/user/list.html");
},
deleteUserById(uid) {
//判断删除的用户是否是登录者
//是 不能删除
//如何判断呢? 登录成功之后 localstorage
//从缓存里面获得用户id
if (uid == this.loginUserId) {
alert("无法删除用户");
return;
}
if (window.confirm("确认要删除吗?" + uid)) {
//发起异步请求 调用后端接口 删除数据库数据
axios.delete(`http://127.0.0.1:9000/api/user/delete/` + uid)
.then(response => {
//页面继续跳转list.html
location.replace("/medical-page/page/user/list.html");
});
}
},
addBtn() {
this.insertUserObj = {
password: "123456",
deptId: "-1",
jobId: "-1",
gender: "0",
};
},
queryAllUserInfo() {
//查询数据库的所有的用户信息 展示list.html
//异步查询
axios.get(`http://127.0.0.1:9000/api/user/query/` + this.page + `/` + this.pageSize)
.then(response => {
let { data } = response.data;
let { page, maxPage, total, list } = data;
this.page = page;
this.maxPage = maxPage;
this.total = total;
this.userList = list;
});
},
queryAllDept() {
axios.get(`http://127.0.0.1:9000/api/dept/query`).then(response => {
let { status, msg, data } = response.data;
if (status == "200") {
this.deptList = data;
}
});
},
queryAllJobInfo() {
axios.get(`http://127.0.0.1:9000/api/job/query`).then(response => {
let { status, msg, data } = response.data;
if (status == "200") {
this.jobList = data;
}
});
},
insertOrUpdateUser() {
//获得用户录入的信息
//异步调用
axios.post(`http://127.0.0.1:9000/api/user/insertOrUpdate`, this.insertUserObj)
.then(response => {
location.replace("/medical-page/page/user/list.html");
});
},
queryUserById(uid) {
//发起异步请求 根据id查询用户信息 查询数据库完整内容
axios.get(`http://127.0.0.1:9000/api/user/query/` + uid)
.then(response => {
let { data } = response.data;
data.userImage = `http://127.0.0.1:9000` + data.userImage;
this.queyUserObj = data;
console.log(this.queyUserObj);
this.insertUserObj = data;
this.queryAllDept();
this.queryAllJobInfo();
});
},
},
created() {
let infoStr = localStorage.getItem("loginUserInfo");
let userObj = JSON.parse(infoStr);
this.trueName = userObj.name;
this.userImage = "http://127.0.0.1:9000" + userObj.image;
let loginUserId = userObj.id;
this.loginUserId = loginUserId;
//查询所有用户信息
//this.queryAllUserInfo();
//created 表示页面加载完毕,立即执行
this.pageHandler(1);
},
});
</script>
引入分页依赖。 pageHelper.jar
<!-- 分页依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
@Data
public class PageResult<T> {
private int page;
private int maxPage; //总页数
private int total;//总记录数
private List<T> list;
}
//查询用户信息,查询部门名称+职位名称
@GetMapping("/query/{page}/{size}")
public AxiosResult<PageResult<SysUserVO>> queryUserAndDeptAndJob(@PathVariable("page") int page,@PathVariable("size") int size) {
PageHelper.startPage(page, size);
List<SysUserVO> userVOList = sysUserMapper.queryUserAndDeptAndJob();
PageInfo<SysUserVO> pageInfo = new PageInfo<>(userVOList);
PageResult<SysUserVO> pageResult = new PageResult<>();
pageResult.setList(userVOList);
pageResult.setPage(page);
pageResult.setMaxPage(pageInfo.getPages());
pageResult.setTotal(pageInfo.getTotal());
return AxiosResult.success(pageResult);
}
1.在搜索框中,成功展示部门以及职位信息 。
2.找到搜索按钮,创建点击事件。
<button type="button" class="btn btn-theme" @click="queryAllUserInfo">搜索</button>
//分页查询用户信息
3.在queryAllUserInfo函数中:
满足实现的功能: 条件+分页
queryAllUserInfo() {
//查询数据库的所有的用户信息 展示list.html
//异步查询
//分页+条件
//1.参数: 分页数据 条件的数据
let params = {
params:{
page: this.page,
pageSize: this.pageSize,
deptId: this.searchParams.deptId,
jobId: this.searchParams.jobId,
nameParam: this.searchParams.nameParam,
phoneOrNumber: this.searchParams.phoneOrNumber,
}
};
axios.get(`http://127.0.0.1:9000/api/user/query`,params)
.then(response => {
// let { data } = response.data;
// let { page, maxPage, total, list } = data;
// this.page = page;
// this.maxPage = maxPage;
// this.total = total;
// this.userList = list;
});
},
调试之后,前端js:
queryAllUserInfo() {
//查询数据库的所有的用户信息 展示list.html
//异步查询
//分页+条件
//1.参数: 分页数据 条件的数据
let params = {
params:{
page: this.page,
pageSize: this.pageSize,
deptId: this.searchParams.deptId,
jobId: this.searchParams.jobId,
nameParam: this.searchParams.nameParam,
phoneOrNumber: this.searchParams.phoneOrNumber,
}
};
axios.get(`http://127.0.0.1:9000/api/user/query`, params)
.then(response => {
let { data } = response.data;
let { page, maxPage, total, list } = data;
this.page = page;
this.maxPage = maxPage;
this.total = total;
this.userList = list;
//搜索相关的信息清除
this.searchParams.deptId=-1;
this.searchParams.jobId=-1;
this.searchParams.nameParam="";
this.searchParams.phoneOrNumber="";
});
},
<tr v-show="userList.length==0">
<td colspan="8">没有找到合适的数据</td>
</tr>
在controller:
//查询用户信息,查询部门名称+职位名称
@GetMapping("/query")
public AxiosResult<PageResult<SysUserVO>> queryUserAndDeptAndJob(SearchParamVO searchParamVO) {
int page = searchParamVO.getPage();
int size = searchParamVO.getPageSize();
PageHelper.startPage(page, size);
//传递条件数据,满足sql编写
List<SysUserVO> userVOList = sysUserMapper.queryUserAndDeptAndJob(searchParamVO);
PageInfo<SysUserVO> pageInfo = new PageInfo<>(userVOList);
PageResult<SysUserVO> pageResult = new PageResult<>();
pageResult.setList(userVOList);
pageResult.setPage(page);
pageResult.setMaxPage(pageInfo.getPages());
pageResult.setTotal(pageInfo.getTotal());
return AxiosResult.success(pageResult);
}
//在mapper接口
List<SysUserVO> queryUserAndDeptAndJob(SearchParamVO searchParamVO);
//在mapper的映射文件中
<select id="queryUserAndDeptAndJob" resultType="com.by.medical.vo.SysUserVO">
SELECT u.*,
d.dept_name,
j.job_name
FROM sys_user AS u,
dept AS d,
job_info AS j
WHERE (u.dept_id = d.id AND u.job_id = j.id)
<if test="deptId!=-1">
AND u.dept_id=#{deptId}
</if>
<if test="jobId!=-1">
AND u.job_id=#{jobId}
</if>
<if test="nameParam!=null and nameParam!=''">
AND u.user_true_name LIKE '%${nameParam}%'
</if>
<if test="phoneOrNumber!=null and phoneOrNumber!=''">
AND (u.phone=#{phoneOrNumber} OR u.job_number=#{phoneOrNumber})
</if>
ORDER BY u.id DESC
</select>
问题: 在用户表中,存在很多外键列。外键列的数据不与我们主表里面的主键列的数据一致的话,我们进行普通关联查询,无法查询到的。为了显示所有用户信息,建议使用外连接。
<select id="queryUserAndDeptAndJob" resultType="com.by.medical.vo.SysUserVO">
SELECT u.*,
d.dept_name,
j.job_name
FROM sys_user AS u left join dept d on d.id = u.dept_id
left join job_info AS j on u.job_id = j.id
<where>
<if test="deptId!=-1">
AND u.dept_id=#{deptId}
</if>
<if test="jobId!=-1">
AND u.job_id=#{jobId}
</if>
<if test="nameParam!=null and nameParam!=''">
AND u.user_true_name LIKE '%${nameParam}%'
</if>
<if test="phoneOrNumber!=null and phoneOrNumber!=''">
AND (u.phone=#{phoneOrNumber} OR u.job_number=#{phoneOrNumber})
</if>
</where>
ORDER BY u.id DESC
</select>
不单独编写上传页面,在新增/修改的模态框的form表单中,新增上传文件元素即可。
<!-- 从模板中复制文件上传按钮 -->
<link rel="stylesheet" href="/medical-page/lib/file-uploader/css/jquery.fileupload.css">
<link rel="stylesheet" href="/medical-page/lib/file-uploader/css/jquery.fileupload-ui.css">
<div class="form-group">
<label class="col-sm-2 control-label">用户头像</label>
<div class="col-sm-8">
<div class="col-sm-2">
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-upload" style="color: white;" ></i>
<span style="color: white;">upload</span>
<input type="file" accept="image/jpeg">
</span>
</div>
<div class="col-sm-2">
<img style="width: 100px; height: 100px; margin-left: 80px;">
</div>
</div>
</div>
uploadImage() {
let element = document.getElementById("uploadFile");
let uploadFile = element.files[0];
//调用后台接口 执行异步上传
//1.post
//2.multipart/form-data 请求头
//3.FormData
let param = new FormData();
param.append('uploadFile', uploadFile);//二进制文件
let config = {
headers: { 'Content-type': 'multipart/form-data' },
};
axios.post(`http://127.0.0.1:9000/api/user/upload`, param, config).then(response => {
let { status, data } = response.data;
console.log(data);
});
},
// uploadImage(e){
// //上传头像
// //1.获得用户选择的头像内容(文件内容)
// //2.将二进制文件内容 传递到后端接口
// //3.js请求接口
// // 3.1 post
// // 3.2 multipart/form-data
// // 3.3 文件数据封装FormData
// let uploadFile = e.target.files[0];
// let formData = new FormData();
// formData.append("uploadFile",uploadFile);
// let config={
// headers:{
// 'content-type':'multipart/form-data',
// }
// };
// //异步上传
// axios.post(`http://127.0.0.1:9000/api/user/upload`,formData,config);
// },
//上传用户头像
@PostMapping("/upload")
public AxiosResult<String> uploadUserImage(MultipartFile uploadFile, HttpServletRequest request) throws IOException {
String originalFilename = uploadFile.getOriginalFilename();//获得上传文件名称以及后缀
//正常开发中:
//1.存储外部服务器 (nginx)
//2.云端服务器(OSS) 对象存储服务器
//后端维护用户上传的图片(本地磁盘)
//把用户每天上传的图片 存储到以日期为准一个目录中
//弊端: 前端页面不能正常访问存储本地磁盘文件
//解决: 需要添加映射处理
// String realPath = request.getServletContext().getRealPath("/");
// System.out.println(realPath);
String curDateStr = LocalDate.now().toString();
File targetDir = new File(UPLOAD_USER_DIR, curDateStr);
if (!targetDir.exists()) {
targetDir.mkdirs();
}
String extension = StringUtils.getFilenameExtension(originalFilename);
String name = UUID.randomUUID().toString().replaceAll("-", "");
String targetFileName = name + "." + extension;
uploadFile.transferTo(new File(targetDir, targetFileName));
return AxiosResult.success("/upload/user/"+curDateStr+"/"+targetFileName);
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceLocations("file:F:\\beiyou\\zhenggong_IT\\workspace\\zhenggong-medical-system\\src\\main\\resources\\static\\upload\\user");
}
}
数据导出: 将数据库/缓存数据导出至excel文件。
数据导入: 将excel文件里面的sheet中的信息导入数据库,永久存储。
需求:
将数据库里面所有用户信息导出到指定的exel文件中。
常用的技术:
easyexcel 入门容易
前端页面
<div class="form-group">
<button class="btn btn-warning" @click="exportUserInfo">
<i class="fa fa-download"></i>导出
</button>
</div>
exportUserInfo() {
//异步请求
myAxios.post(`http://127.0.0.1:9000/api/user/export`).then(response => {
//创建下载提示 将成功返回的内容下载到文件中
//后端响应的类型 应该是字节 blob
let data = response.data;
const blob = new Blob([data], {
type: "application/vnd.ms-excel;charset=utf-8",
});
//blob就是获得到字节内容
let downloadLink = document.createElement("a");
downloadLink.href = window.URL.createObjectURL(blob);
downloadLink.download = "导出用户信息.xlsx";
downloadLink.click();//自动下载到 "导出用户信息.xlsx"
//问题: 下载文件成功 可能会出现文件打不开
//原因: axios发起异步请求 默认返回的json的数据 也就是说获得的data是json的数据
});
},
let myAxios = axios.create({
responseType:"blob",
});
后端
<!--引入easyexcel的依赖-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
//导出---->将用户信息导出到指定的文件中
@PostMapping("/export")
public void exportUserInfo(HttpServletResponse response) throws IOException {
//获得导出的所有用户信息
List<SysUser> sysUserList = sysUserMapper.queryAll();
ExportParams params = new ExportParams();
params.setTitle("用户列表信息");
params.setSheetName("用户sheet");
Workbook workbook = ExcelExportUtil.exportExcel(params, SysUser.class, sysUserList);
//配置响应
response.setCharacterEncoding("UTF-8");
response.setHeader("content-type","application/vnd.ms-excel");
//服务器响应的不再是json数据,而是流文件(excel)文件
String fileName = URLEncoder.encode("userInfo", StandardCharsets.UTF_8);
response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
@Data
public class SysUser implements java.io.Serializable{
private Integer id;
//name的数据是对应的excel文件里面的列名
//orderNum是用来定义excel的第n列 从0开始
//width用来定义列的宽度
@Excel(name = "用户名",orderNum = "1",width = 20)
private String userTrueName;
private String password;
@Excel(name = "工号",orderNum = "0")
private String jobNumber;
@Excel(name = "性别",replace = {"男_0","女_1"},orderNum = "2")
private Integer gender;
@Excel(name = "手机号",orderNum = "3",width = 20)
private String phone;
@Excel(name = "邮箱账号",orderNum = "4",width = 20)
private String email;
@Excel(name = "微信",orderNum = "5",width = 20)
private String wechat;
private String qqNumber;
private String userImage;
@Excel(name = "家庭地址",orderNum = "6",width = 20)
private String address;
private Integer deptId;
private Integer jobId;
private Integer regionId;
private Integer provinceId;
private Integer groupId;
private Integer productGroupId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "入职时间",orderNum = "7",exportFormat = "yyyy-MM-dd HH:mm:ss",width = 30)
private java.time.LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private java.time.LocalDateTime updateTime;
}
导入:
将指定的excel文件里面用户信息,保存到数据库中。
excel文件内容是有模板要求(数据必须按照模板要求)-----> 将excel文件进行上传----> 调用sql 将数据存储
前端(页面,js)
<div class="form-group">
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-upload" style="color: white;"></i>
<span style="color: white;">导入</span>
<input type="file" class="" accept=".xls,.xlsx" @change="importUserInfo">
</span>
</div>
importUserInfo(event) {
//异步调用接口 实现导入
//1.获得用户选择的文件
//2.将文件内容传到服务器
//3.调用接口
//等价于====> 文件上传
// FormData post multipart/form-data
let importFile = event.target.files[0];
let formData = new FormData();
formData.append("importFile", importFile);
let config = {
headers: {
"content-type": "multipart/form-data",
}
};
axios.post(`http://127.0.0.1:9000/api/user/import`, formData, config).then(response => {
location.replace("/medical-page/page/user/list.html");
});
},
后端
//导入----->将excel文件数据存储到数据库
@PostMapping("/import")
public AxiosResult<?> importUserInfo(MultipartFile importFile) throws Exception {
//将页面提价的文件数据转成多个用户对象
// System.out.println(importFile.getOriginalFilename());
// System.out.println(importFile.getBytes().length);
// System.out.println(importFile.getSize());
//将文件里面的每一行内容转换SysUser对象
//调用mapper接口 实现批量插入用户信息
//前提:
// 1.引入easypoi的依赖 2.SysUser的相关的属性使用@Excel修饰
// 2.excel文件里面的列名不能随便写 必须与SysUser类中@Excel的name的值一致
//importExcel(InputStream inputstream, Class<?> pojoClass,ImportParams params)
//inputstream 文件内容
ImportParams importParams = new ImportParams();
importParams.setStartSheetIndex(0);//指定读取第index+1个sheet
importParams.setTitleRows(1);//标题
importParams.setHeadRows(1);//头部 列
List<SysUser> sysUserList = ExcelImportUtil.importExcel(importFile.getInputStream(), SysUser.class, importParams);
//将流的内容转换成指定的类型对象
//sysUserList.forEach(System.out::println);
//批量新增
sysUserList.forEach(sysUser -> sysUser.setPassword("123456"));
//sysUserList.forEach(System.out::println);
sysUserMapper.insertUserBatch(sysUserList);
return AxiosResult.success();
}
void insertUserBatch(List<SysUser> sysUserList);
<insert id="insertUserBatch">
INSERT INTO sys_user
(user_true_name, `password`, job_number, gender, phone, email, wechat, qq_number, address, dept_id, job_id)
values
<foreach collection="sysUserList" item="user" separator=",">
(#{user.userTrueName}, #{user.password}, #{user.jobNumber}, #{user.gender}, #{user.phone}, #{user.email},
#{user.wechat}, #{user.qqNumber},
#{user.address}, #{user.deptId}, #{user.jobId})
</foreach>
</insert>
MD5: MessageDigest 信息摘要算法
不可逆的。
Base64
修改密码 只能修改个人密码。
前端页面
<div class="form-group">
<button class="btn btn-warning" @click="editPassBtn"
data-toggle="modal" data-target="#editPassModal" >
<i class="fa fa-download"></i>修改密碼
</button>
</div>
updatePass(){
let params = {
id:this.loginUserId,
newPass:this.newPass,
};
console.log(params);
axios.post(`http://127.0.0.1:9000/api/user/pass`,params).then(response=>{
//跳轉到login.html
//清除緩存裡面個人信息
//localStorage.clear();
localStorage.removeItem("loginUserInfo");
location.replace("/medical-page/login.html");
});
},
后端
public class MD5Util {
private MD5Util(){}
private static final String SALT = "%$**&7lISA^^^^524";
/**
* 密码加密
* @param sourceStr 源密码
* @return 加密之后的数据
*/
public static String encodeStr(@NonNull String sourceStr){
try {
sourceStr+=SALT;
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(sourceStr.getBytes());
byte[] bytes = messageDigest.digest();//加密的数据
//换算
//将字节转换成16进制里面字符
//一个字节转换成2个16进制的字符
BigInteger bigInteger = new BigInteger(1,bytes);
return bigInteger.toString(16);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
//修改密码
@PostMapping("/pass")
public AxiosResult<?> updatePass(@RequestBody Map<String,Object> map){
Object id = map.get("id");
Object newPass = map.get("newPass");//用户设置的新密码 是明文数据
//对密码加密
String encodeStr = MD5Util.encodeStr(newPass.toString());
sysUserMapper.updatePass((int)id,encodeStr);
return AxiosResult.success();
}
注意: 登录,新增,导入的功能中,也要对密码加密。
代码略
<!--引入jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
public class TokenService {
private static final String SECRET = "^%$LISA(($#$";
//生成token
public String createToken(long adminId) {
Algorithm algorithm = Algorithm.HMAC256(SECRET);
return JWT.create()
.withIssuer("lisa")
.withSubject("登录成功的token")
.withClaim("adminId",adminId)
//.withExpiresAt(new Date(System.currentTimeMillis() + Duration.ofMinutes(2).toMillis()))
.sign(algorithm);
}
//验证token
public DecodedJWT verifyToken(String token) {
Algorithm algorithm = Algorithm.HMAC256(SECRET);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("lisa")
.build();
return verifier.verify(token);
}
}
@Component //注入容器
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//token验证
//在项目中 获得请求头里面的token
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
return true;
}
String authorization = request.getHeader("Authorization");
if (!StringUtils.hasLength(authorization)) {//是空
//建议抛出异常 进行全局异常处理
throw new RuntimeException("用户未登录");
//return false;
}
String[] array = authorization.split(" ");
if (array.length == 0) {
throw new RuntimeException("用户未登录");
}
if (!array[0].startsWith("Basic")) {
throw new RuntimeException("用户未登录");
}
try {
tokenService.verifyToken(array[1]);
} catch (Exception e) {
throw new RuntimeException("用户未登录", e);
}
return true;
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceLocations("file:F:\\beiyou\\zhenggong_IT\\workspace\\zhenggong-medical-system\\src\\main\\resources\\static\\upload\\user");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/user/login")
.order(0);
}
}
//{ status:"200",msg:"查询成功",data:userObj}
//{ status:"500",msg:"查询失败"}
@Getter
@Setter
//@JsonSerialize
public class AxiosResult<T> implements Serializable {
//就是封装服务器响应给前端的数据
//T就是一个参数化数据类型 <T> 泛型 可以是任意一个引用数据类型
private String status;
private String msg;
private T data;
private AxiosResult(StatusEnum statusEnum){
this.status = statusEnum.getStatus();
this.msg = statusEnum.getMsg();
}
private AxiosResult(StatusEnum statusEnum,T data){
this.status = statusEnum.getStatus();
this.msg = statusEnum.getMsg();
this.data = data;
}
//静态方法 success error
public static <T> AxiosResult<T> success() {
return new AxiosResult<>(StatusEnum.SUCCESS);
}
public static <T> AxiosResult<T> success(T data) {
return new AxiosResult<>(StatusEnum.SUCCESS,data);
}
public static <T> AxiosResult<T> success(StatusEnum statusEnum,T data) {
return new AxiosResult<>(statusEnum,data);
}
public static <T> AxiosResult<T> error() {
return new AxiosResult<>(StatusEnum.ERROR);
}
public static <T> AxiosResult<T> error(StatusEnum statusEnum) {
return new AxiosResult<>(statusEnum);
}
}
@Getter
@AllArgsConstructor
public enum StatusEnum {
//维护当前系统里面所有的错误码列表
SUCCESS("200","成功"),
ERROR("500","失败"),
USER_LOGIN_ERROR("501","用户名或者密码有误");
private final String status;
private final String msg;
}
url:
协议 ip 端口
list.html:1 Access to XMLHttpRequest at 'http://127.0.0.1:9000/api/dept/query' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
@Configuration
public class CorsConfig {
//Filter------>CorsFilter
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("http://127.0.0.1:5500");
//corsConfiguration.setAllowedOrigins();
corsConfiguration.setAllowedMethods(List.of("POST", "GET", "PUT", "DELETE", "OPTION"));
corsConfiguration.addAllowedHeader("*");
corsConfiguration.setAllowCredentials(false);
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**", corsConfiguration);
CorsFilter corsFilter = new CorsFilter(configurationSource);
bean.setFilter(corsFilter);
bean.setOrder(0);
return bean;
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。