文章目录
SSM——用户信息管理系统
源码链接:用户信息管理系统
1 核心功能
- 登录、注册
- 添加用户信息
- 删除某一个用户信息
- 删除选中的用户信息
- 分页查询所有用户信息
- 模糊查询用户信息
- 更新用户信息
2 整体架构:
项目整体基于HTTP协议,前端使用 HTML+CSS+JS 构建页面整体布局,后端采用分层结构,分为Controller层,Service层,Dao层,
采用SpringBoot+SpringMvc+Mybatis来实现,达到在设计上的高内聚低耦合。
3 数据库表设计
drop database if exists usermanager;
create DATABASE if not exists usermanager character set utf8;
use usermanager;
drop table if exists usermessage;
create table `usermessage` (
`id` INT PRIMARY KEY auto_increment,
`name` varchar (60),
`username` varchar (60) default 'bit',
`password` varchar (60) default '123456',
`gender` varchar (4),
`age` int,
`address` varchar (90),
`qq` varchar (20),
`email` varchar (30)
);
INSERT INTO usermessage VALUES(1,'张飞','zhangfei','123','男',18,'成
都','1262913815','126@qq.com');
INSERT INTO usermessage VALUES(2,'关羽','guanyu','1234','男',18,'陕
西','1262913816','1262@qq.com');
INSERT INTO usermessage VALUES(3,'张三','zhangsan','1235','女',19,'陕
西','1262913817','1263@qq.com');
4 创建实体类(POJO)
User: 用户信息
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String username;
private String password;
private String gender;
private int age;
private String address;
private String qq;
private String email;
}
PageBean:用来返回给前端信息
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageBean<T> {
private int totalCount; //总记录数
private int totalPage; //总页码
private List<T> list; //每页中的数据
private int currentPage;//当前页码
private int rows; //每页的记录数
}
5 UserMapper接口
@Service
public interface UserMapper {
//注册
int register(User registerUser);
//登录
User login(User loginUser);
//增加用户
int add(User addUser);
//删除
int delete( int id);
//根据id查找
User find(int id);
//更新
int update(User updateUser);
//查询共有多少条记录
int findAllRecord(HashMap<String,Object> map);
//分页查询 map:包含:currentPage、rows、name、address、email
List<User> findByPage(HashMap<String,Object> map);
}
6 编写UserMapper.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.glp.dao.UserMapper">
<!--注册-->
<insert id="register" parameterType="user">
insert into usermessage(name,username,password,gender,age,address,qq,email) values(#{name},#{username},#{password},#{gender},#{age},#{address},#{qq},#{email})
</insert>
<!--分页查询-->
<!--select * from usermessage where 1=1 and name like ? and address like ? and email like ?
limit ?,?-->
<select id="findByPage" parameterType="map" resultType="user">
select * from usermessage
<where>
<if test="name!=null">
name like concat('%',#{name},'%')
</if>
<if test="address!=null">
and address like concat('%',#{address},'%')
</if>
<if test="email!=null">
and email like concat('%',#{email},'%')
</if>
</where>
limit #{startIndex},#{rows}
</select>
</mapper>
注:
-
分页查询时采用了动态SQL,并且这里需要注意一下模糊查询时的sql注入问题,
编写动态SQL时,最好先将原SQL写出来。 -
为了方便分页查询时的传参,这里采用了HashMap进行传参
7 配置SpringBoot (application.properties)
debug=true
# 设置打印日志的级别,及打印sql语句
logging.level.root=INFO
logging.level.druid.sql.Statement=ERROR
logging.level.com.glp=DEBUG
#springmvc配置参数
spring.mvc.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#配置数据库连接池初始化参数
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/usermanager?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=mysql
#给实体类起别名,别名默认为原名小写
mybatis.type-aliases-package = com.glp.pojo
#指明mapper.xml文件在哪里
mybatis.mapper-locations=classpath:mapper/*.xml
#自定义根路径
server.servlet.context-path:/usermanagers
8 service层设计
service层不仅是对Dao层的直接引用,在这里一般需要做一些逻辑上的处理。
(1)service层接口
service层接口:UserService
@Service
public interface UserService {
//注册
int register(User registerUser);
//登录
User login(User loginUser);
//增加用户
int add(User addUser);
//删除
int delete(int id);
//根据id查找,用来判断user是否存在,如果存在,就继续执行下面的returnFront,及update
User find(int id);
//负责将find查到的user,通过session传给前端,在controller中进行处理
//更新
int update(User updateUser);
//查询共有多少条记录
int findAllRecord(HashMap<String,Object> map);
//分页查询 map:包含:currentPage、rows、name、address、email
PageBean<User> findAllByPage(HashMap<String,Object> map);
}
其他的接口基本上都和Dao层接口类似,所以直接调用dao层的接口即可。因此这里我们只讨论分页查询部分,这里采用分页查询时,我们采用findAllByPage
对dao层的结果进行逻辑处理.
(2)UserServiceImpl
service层实现类:UserServiceImpl
@Service
public class UserServiceImpl implements UserService{
@Resource
private UserMapper userMapper;
@Override
public int register(User registerUser) {
return userMapper.register(registerUser);
}
@Override
public User login(User loginUser) {
return userMapper.login(loginUser);
}
@Override
public int findAllRecord(HashMap<String,Object> map) {
return userMapper.findAllRecord(map);
}
//在service层做逻辑整合
@Override
public PageBean<User> findAllByPage(HashMap<String,Object> map) {
PageBean<User> pageBean=new PageBean<>();
int rows = (int)map.get("rows");
int currentPage = (int)map.get("currentPage");
//查询当前搜索中共有多少条记录
int allRecord = findAllRecord(map);
//计算总共的页数
int totalPage;
if(allRecord%rows==0){
totalPage=allRecord/rows;
}else{
totalPage=allRecord/rows+1;
}
//分页查询:返回用户数据,及总页数,当前页数,一页的行数。
int start=(currentPage-1)*rows;
map.put("startIndex",start);
List<User> users = userMapper.findByPage(map);
pageBean.setCurrentPage(currentPage);
pageBean.setList(users);
pageBean.setRows(rows);
pageBean.setTotalCount(allRecord);
pageBean.setTotalPage(totalPage);
return pageBean;
}
}
通过Dao层的findAllRecord(map);
来根据前端得到的name,address,email进行模糊查询,用来查出当前条件下查询出的总条数。
这里需要进行逻辑处理,是因为分页查询时,需要知道分页limit
的 起始点startIndex。
同时我们需要计算 总页数 ,以及将分页查询的所有User封装到pageBean中,以在controller层传给前端。
9 Controller层设计
(1)注册,登录,添加,删除单个用户
比较简单,不做讨论
@Controller
public class UserController {
@Resource
private UserServiceImpl userService;
//注册用户
@RequestMapping("/registerServlet")
public void register(HttpServletRequest req, HttpServletResponse resp,User u) throws IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
Writer writer = resp.getWriter();
int ret =userService.register(u);
if(ret == 0) {
System.out.println("注册失败!");
writer.write("<h2> 注册失败 </h2>" );
}else {
System.out.println("注册成功!");
resp.sendRedirect("/usermanagers/login.html");
}
}
}
(2)修改用户
修改用户时,在list.html中通过点击修改页面,访问/findUserServlet
,查询用户是否存在,如果存在则将用户写入Session中。
//查看要修改的对象是否存在,如果存在就将该对象存入session中
@RequestMapping("/findUserServlet")
public String findIfNeedUpdate(HttpServletRequest req,HttpServletResponse resp,int id) throws UnsupportedEncodingException {
req.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
User user = userService.find(id);
if(user == null) {
System.out.println("没有要修改的对象!");
}else {
//将要修改的对象存入session中
req.getSession().setAttribute("updateUser",user);
return "redirect:/update.html"; //通过update.html调用updateServlet
}
return "redirect:/list.html";
}
如果存在该用户,就通过重定向转到update.html页面,在update.html页面通过ajax访问/returnServlet
,拿到sessiong中的user信息,将信息返回给前端:
//在更新用户的时候,通过访问returnServlet拿到要修改的user对象,并将该对象填入前端界面中
@RequestMapping("/returnServlet")
public void returnFront(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
Object updateUser = req.getSession().getAttribute("updateUser");
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(),updateUser);
}
当点击提交按钮时,会触发ajax访问/updateServlet
,进行真正的修改操作:
//如果该用户存在,就可以通过update.html,进入/updateServlet
@RequestMapping("/updateServlet")
public void updateUser(HttpServletRequest req,HttpServletResponse resp,User user) throws IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
//还要从session中拿到要修改的id
User sessionUser = (User)req.getSession().getAttribute("updateUser");
int id = sessionUser.getId();
user.setId(id);
int ret = userService.update(user);
Map<String,Object> return_map=new HashMap<>();
if (ret==1){
return_map.put("msg",true);
}else{
return_map.put("msg",false);
}
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),return_map);
}
(3)批量删除用户:
在controller层中直接写(不在service层处理),删除选中的所有用户,也是通过service中的delete方法,会将前端传过来的id数组,逐个删除。
@RequestMapping("/deleteSelectedServlet")
public void deleteAllSelect(HttpServletRequest req,HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
//获取数组id
String[] values = req.getParameterValues("id[]");
int sum=0;
Map<String,Object> map=new HashMap<>();
for(int i=0;i<values.length;i++){
int j = Integer.parseInt(values[i]);
//调用Service层方法删除
int delete = userService.delete(j);
sum=sum+delete;
}
if(sum==values.length){
//证明删除成功
map.put("msg",true);
}else {
map.put("msg",false);
}
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(),map);
}
查询操作结束后,将选中的id保存到Array数组中.通过ajax函数返回给后端,在controller层通过req.getParameterValues("id[]");
获取id数组,然后调用service层的delete方法,对每个id对应的用户进行删除。
(4)分页模糊查询
//分页+模糊查询
@RequestMapping("/findByPageServlet")
public void findUserByPage(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
//rows,currentPage,name,address,email
String rows = req.getParameter("rows");
String currentPage = req.getParameter("currentPage");
String name = req.getParameter("name");
String address = req.getParameter("address");
String email = req.getParameter("email");
Integer rowsInt = Integer.valueOf(rows);
Integer currentPageInt = Integer.valueOf(currentPage);
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("rows",rowsInt);
map.put("currentPage",currentPageInt);
map.put("name",name);
map.put("address",address);
map.put("email",email);
PageBean<User> allByPage = userService.findAllByPage(map);
//传给前端
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),allByPage);
}
}
这里通过map的方式将前端获取的数据传给service层的findAllByPage
方法;
点击查询按钮时的操作:
一开始进入list.html页面时会默认调用下面这个函数,5代表一页的行数,1代表当前页。
注:
调用完Service层的findAllByPage(map)方法后,会得到前端需要的pageBean当前页面信息,包括用户信息list<User>
,总页数totalPage,总记录数totalCount,当前页currentPage,每页行数rows。这里我们通过ObjectMapper
以json形式传递给前端。
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),allByPage);
10 用户登录状态拦截——拦截器
项目布置完后,发现我们不用登录也可以直接访问后面的list.html等内容,为此我们选择在项目中增加一个登录验证的部分——拦截器。
(1)LoginInterceptor
拦截到请求后,检查是否登录过(通过用户的Session信息),登录过则直接返回ture,允许继续访问;没有登录则直接跳转到登录页面。
package com.glp.config;
@Component //注册到Spring容器中
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try{
HttpSession session = request.getSession();
User user = (User)session.getAttribute("user");
if(user!=null){
return true;
}
//登录不成功,直接跳转到登录页面
response.sendRedirect(request.getContextPath()+"/login.html");
}catch (IOException o){
o.printStackTrace();
}
return false;
}
}
(2)MyConfig
package com.glp.config;
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加一个拦截器
registry.addInterceptor(loginInterceptor).
// 拦截配置
addPathPatterns("/**").
// 排除配置
excludePathPatterns("/**/loginServlet").
excludePathPatterns("/**/registerServlet").
excludePathPatterns("/**/login.html").
excludePathPatterns("/**/register.html").
excludePathPatterns("/**/*.js")
.excludePathPatterns("/**/*.css").
excludePathPatterns("/**/*.png").
excludePathPatterns("/**/*.jpg");
}
addInterceptor
:添加一个拦截器,将拦截下来的路径交给它来处理
addPathPatterns
: 拦截配置
excludePathPatterns:
排除配置
排除配置中主要将登录和注册的静态页面Html以及servlet请求中的动态页面都给放行,对于其他的页面都要进行拦截。
注意我们在拦截时采用了addPathPatterns("/**")
.,即所有的内容都给拦截包括静态内容,为了简单起见,在这里我们直接采用暴力的方法,对我们所要用到的静态内容,js,css,png,jpg等都给放行,