Java项目——云R记
Java入门级项目:云R记
视频地址
https://www.bilibili.com/video/BV1YU4y1p7wj?from=search&seid=1307576622141006226&spm_id_from=333.337.0.0
完整代码
https://github.com/ShadowLim/Java_Project
1、项目介绍
- 云R记软件就是用于记录日常生活点滴。一款简单快速的个人记事备忘工具。会议记录、日程安排、生活备忘,奇思妙想、快乐趣事以及任何突发灵感都可快速记录到系统中。
- 本系统采用B/S 架构,使用 BootStrap + Jsp + Servlet + MySQL+ Tomcat
开发,使用 Maven构建,采用 Junit单元测试、Log4j搭建日志、使用POI导入导出报表,操作 DB 使用大名鼎鼎的 DBUtil。 - 本项目包含用户模块、类型模块、云记模块、数据报表、首页模块这几个核心模块,核心主旨是掌握功能的分析以及前后台数据交互。
2、需求分析
tb_note表
字段名称 | 字段类型 | 字段描述 |
---|---|---|
noteId | int | 主键,自增 |
title | varchar | 标题 |
content | text | 内容 |
typeId | int | 外键,从属tb_note_type |
pubTime | timestamp | 发布时间 |
lon | float | 经度 |
lat | float | 纬度 |
tb_note_type表
字段名称 | 字段类型 | 字段描述 |
---|---|---|
typeId | int | 主键,自动增长 |
typeName | varchar | 类别名,在同一个用户下唯一 |
userId | int | 从属用户 |
tb_user表
字段名称 | 字段类型 | 字段描述 |
---|---|---|
userId | int | 主键,自动增长 |
uname | varchar | 用户名 |
upwd | varchar | 密码 |
nick | varchar | 昵称 |
head | varchar | 头像 |
mood | varchar | 心情 |
3、 环境搭建
3.1 创建项目
- 3.1.1 新建项目:
选择 “File” ——> “New” ——> “Project…” ,选择 “Maven”,设置 JDK 版本,选择 Maven Web 项目的模板
-
3.1.2 配置Maven:
-
3.1.3 设置项目信息:
设置项目的名称、存放的工作空间,以及对应的 GroupId
- 3.1.4 项目结构
创建好 Maven Web项目之后,对应的目录结构如下:
- 3.1.5 修改配置
在 pomx.xml 配置文件中,修改配置、添加依赖与插件
4.0.0 com.lezijie lezijie-note 1.0-SNAPSHOT war lezijie-note Maven Webapp http://www.example.com UTF-8 1.8 1.8 junit junit 4.12 test javax.servlet javax.servlet-api 4.0.1 provided org.slf4j slf4j-log4j12 1.7.2 org.slf4j slf4j-api 1.7.2 mysql mysql-connector-java 8.0.19 com.alibaba fastjson 1.2.62 cn.hutool hutool-all 5.4.7 commons-io commons-io 2.4 commons-fileupload commons-fileupload 1.3.1 javax.servlet jstl 1.2 org.projectlombok lombok 1.18.12 provided lezijie-note org.apache.maven.plugins maven-compiler-plugin 2.3.2 1.8 1.8 UTF-8 org.apache.tomcat.maven tomcat7-maven-plugin 2.1 8080 /note tomcat7
3.2 分层思想
- 在项目的 src/main 目录下,新建 java 目录(源文件夹)与 resources 目录 (资源文件夹)。
- 定义包结构
- Java 的几种对象(PO,VO,DAO,BO,POJO)解释
- PO:
persistant object 持久对象,可以看成是与数据库中的表相映射的 Java 对象。
最简单的 PO 就是对应数据库中某个表中的一条记录,多个记录可以用 PO 的集合。
PO 中应该不包含任何对数据库的操作。 - VO:
value object 值对象。通常用于业务层之间的数据传递,和 PO 一样也是仅仅包含数据而已。
但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要。 - DAO:
data access object 数据访问对象,此对象用于访问数据库。
通常和PO结合使用,DAO 中包含了各种数据库的操作方法。
通过它的方法,结合 PO 对数据库进行相关的操作。 - BO:
business object 业务对象,封装业务逻辑的 java 对象。
通过调用 DAO 方法,结合 PO,VO 进行业务操作。 - POJO:
plain ordinary Java object 简单无规则 java 对象。
3.3 数据库连接
- 配置文件
在 src/main/resources 目录下,新建 db.properties 文件
# 连接MYSQL数据库的配置文件 注:等号的前后不要写空格# 驱动名jdbcName=com.mysql.cj.jdbc.Driver# 数据库连接 ( db_lezijie_note是数据库的名称)dbUrl=jdbc:mysql://localhost:3306/db_lezijie_note?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false# 数据库的连接账号 (账号基本上都是root)dbName=root# 数据库的连接密码 (每个人的数据库密码可能不一致,需要修改)dbPwd=root1234
- 编写 DBUtil
在 com.lezijie.note.util 目录下,新建 Java 类
package com.lezijie.note.util;import java.io.InputStream;import java.sql.*;import java.util.Properties;/** * 乐字节:专注线上IT培训 * 需要视频资料,请添加:lezijie007 */public class DBUtil { // 得到配置文件对象 private static Properties properties = new Properties(); static { try { // 加载配置文件(输入流) InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db.properties"); // 通过load()方法将输入流的内容加载到配置文件对象中 properties.load(in); // 通过配置文件对象的getProperty()方法获取驱动名,并加载驱动 Class.forName(properties.getProperty("jdbcName")); } catch (Exception e) { e.printStackTrace(); } } /** * 获取数据库连接 * @return */ public static Connection getConnetion() { Connection connection = null; try { // 得到数据库连接的相关信息 String dbUrl = properties.getProperty("dbUrl"); String dbName = properties.getProperty("dbName"); String dbPwd = properties.getProperty("dbPwd"); // 得到数据库连接 connection = DriverManager.getConnection(dbUrl, dbName, dbPwd); } catch (SQLException throwables) { throwables.printStackTrace(); } return connection; } /** * 关闭资源 * @param resultSet * @param preparedStatement * @param connection */ public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) { try { // 判断资源对象如果不为空,则关闭 if (resultSet != null) { resultSet.close(); } if (preparedStatement != null) { preparedStatement.close(); } if (connection != null) { connection.close(); } } catch (Exception e) { e.printStackTrace(); } }}
3.4 单元测试
- 3.4.1 测试目录
在 src/main 目录下,新建 test 目录(测试目录),新建 java 目录(测试源文件夹)
- 3.4.2 测试数据库
在 test/java 目录的 com.lezijie.note 包下,新建测试类
/*** 单元测试类*/public class TestDB {@Testpublic void testConnection() {System.out.println(DBUtil.getConnection());}}
3.5 使用日志
- 配置文件
在 src/main/resources 目录下,新建 log4j.properties 文件
### 设置###stdout,log4j.rootLogger = all,D,E,stdout### 输出信息到控制台 ###log4j.appender.stdout = org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n### 输出DEBUG 级别以上的日志到=D://logs/log.log ###log4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.File = D://logs/log.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### 输出ERROR 级别以上的日志到=E://logs/error.log ###log4j.appender.E = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.File =E://logs/error.loglog4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ]
观察D和E盘会发现有「D://logs/log.log」和「E://logs/error.log」两个文件生成。
- 使用方式
下面两个代码均贴在上方的TestDB.java中
// 使用日志工厂类,记入日志private static Logger logger = LoggerFactory.getLogger(DBUtil.class);
// 记录日志logger.info("在{}时,获取数据库连接", new SimpleDateFormat("yyyy-MM-ddHH:mm:ss").format(new Date()));
4、 用户模块
用户模块通过用户行为来区分 actionName用户登录 login进入个人中心 userCenter加载头像 userHead验证昵称的唯一性 checkNick修改用户信息 updateUser用户退出 logout
在 src/main/wabapp 目录下, 新建 statics 文件夹,将静态资源拷贝进来(js、css、images及相关插
件)
5、 类型模块
- 通过用户行为来区分 actionName
- 查询类型列表 list
- 删除类型 delete
- 添加/修改类型 addOrUpdate
6、 云记模块
- 通过用户行为来区分 actionName
- 进入发布云记页面 view
- 添加或修改云记 addOrUpdate
- 查询云记详情 detail
- 删除云记 delete
- 分页查询云记列表 list
7、云记主页模块
- 标题查询云记列表
- 日期分组查询云记列表
- 类型分组查询云记列表
8、 报表统计模块
- 用户发布云记位置的散点图
- 云记发布月份的柱状图
9、代码实现
9.1 note目录
9.1.1 dao层
- BaseDao
package com.lezijie.note.dao;import com.lezijie.note.util.DBUtil;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.util.ArrayList;import java.util.List;/** * 基础的JDBC操作类 * 更新操作 (添加、修改、删除) * 查询操作 * 1. 查询一个字段 (只会返回一条记录且只有一个字段;常用场景:查询总数量) * 2. 查询集合 * 3. 查询某个对象 */public class BaseDao { /** * 更新操作 * 添加、修改、删除 * 1. 得到数据库连接 * 2. 定义sql语句 (添加语句、修改语句、删除语句) * 3. 预编译 * 4. 如果有参数,则设置参数,下标从1开始 (数组或集合、循环设置参数) * 5. 执行更新,返回受影响的行数 * 6. 关闭资源 * * 注:需要两个参数:sql语句、所需参数的集合 * * @param sql * @param params * @return */ public static int executeUpdate(String sql, List params) { int row = 0; // 受影响的行数 Connection connection = null; PreparedStatement preparedStatement = null; try { // 得到数据库连接 connection = DBUtil.getConnetion(); // 预编译 preparedStatement = connection.prepareStatement(sql); // 如果有参数,则设置参数,下标从1开始 if (params != null && params.size() > 0) { // 循环设置参数,设置参数类型为Object for (int i = 0; i < params.size(); i++){ preparedStatement.setObject(i+1, params.get(i)); } } // 执行更新,返回受影响的行数 row = preparedStatement.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 DBUtil.close(null, preparedStatement, connection); } return row; } /** * 查询一个字段 (只会返回一条记录且只有一个字段;常用场景:查询总数量) * 1. 得到数据库连接 * 2. 定义sql语句 * 3. 预编译 * 4. 如果有参数,则设置参数,下标从1开始 (数组或集合、循环设置参数) * 5. 执行查询,返回结果集 * 6. 判断并分析结果集 * 7. 关闭资源 * * 注:需要两个参数:sql语句、所需参数的集合 * * @param sql * @param params * @return */ public static Object findSingleValue(String sql, List params) { Object object = null; Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 获取数据库连接 connection = DBUtil.getConnetion(); // 预编译 preparedStatement = connection.prepareStatement(sql); // 如果有参数,则设置参数,下标从1开始 if (params != null && params.size() > 0) { // 循环设置参数,设置参数类型为Object for (int i = 0; i < params.size(); i++){ preparedStatement.setObject(i+1, params.get(i)); } } // 执行查询,返回结果集 resultSet = preparedStatement.executeQuery(); // 判断并分析结果集 if (resultSet.next()) { object = resultSet.getObject(1); } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 DBUtil.close(resultSet, preparedStatement, connection); } return object; } /** * 查询集合 (JavaBean中的字段与数据库中表的字段对应) * 1. 获取数据库连接 * 2. 定义SQL语句 * 3. 预编译 * 4. 如果有参数,则设置参数,下标从1开始 (数组或集合、循环设置参数) * 5. 执行查询,得到结果集 * 6. 得到结果集的元数据对象(查询到的字段数量以及查询了哪些字段) * 7. 判断并分析结果集 * 8. 实例化对象 * 9. 遍历查询的字段数量,得到数据库中查询到的每一个列名 * 10. 通过反射,使用列名得到对应的field对象 * 11. 拼接set方法,得到字符串 * 12. 通过反射,将set方法的字符串反射成类中的指定set方法 * 13. 通过invoke调用set方法 * 14. 将对应的JavaBean设置到集合中 * 15. 关闭资源 * @param sql * @param params * @param cls * @return */ public static List queryRows(String sql, List params, Class cls) { List list = new ArrayList(); Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try{ // 得到数据库连接 connection = DBUtil.getConnetion(); // 预编译 preparedStatement = connection.prepareStatement(sql); // 如果有参数,则设置参数,下标从1开始 if (params != null && params.size() > 0) { // 循环设置参数,设置参数类型为Object for (int i = 0; i < params.size(); i++){ preparedStatement.setObject(i+1, params.get(i)); } } // 执行查询,返回结果集 resultSet = preparedStatement.executeQuery(); // 得到结果集的元数据对象(查询到的字段数量以及查询了哪些字段) ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); // 得到查询的字段数量 int fieldNum = resultSetMetaData.getColumnCount(); // 判断并分析结果集 while (resultSet.next()) { // 实例化对象 Object object = cls.newInstance(); // 遍历查询的字段数量,得到数据库中查询的每一个列名 for (int i = 1; i <= fieldNum; i++) { // 得到查询的每一个列名 // getColumnLabel():获取列名或别名 // getColumnName():获取列名 String columnName = resultSetMetaData.getColumnLabel(i); // 如果是tb_user,userId字段 // 通过反射,使用列名得到对应的field对象 Field field = cls.getDeclaredField(columnName); // 拼接set方法,得到字符串 String setMethod = "set" + columnName.substring(0,1).toUpperCase() + columnName.substring(1); // 通过反射,将set方法字符串反射成类中对应的set方法 Method method = cls.getDeclaredMethod(setMethod, field.getType()); // 得到查询的每一个字段对应的值 Object value = resultSet.getObject(columnName); // 通过invoke方法调用set方法 method.invoke(object, value); } // 将Javabean设置到集合中 list.add(object); } } catch (Exception e) { e.printStackTrace(); } finally { DBUtil.close(resultSet, preparedStatement, connection); } return list; } /** * 查询对象 * @param sql * @param params * @param cls * @return */ public static Object queryRow(String sql, List params, Class cls) { List list = queryRows(sql, params, cls); Object object = null; // 如果集合不为空,则获取查询的第一条数据 if (list != null && list.size() > 0) { object = list.get(0); } return object; }}
- NoteDao
package com.lezijie.note.dao;import cn.hutool.core.util.StrUtil;import com.lezijie.note.po.Note;import com.lezijie.note.vo.NoteVo;import java.util.ArrayList;import java.util.List;public class NoteDao { /** * 添加或修改云记,返回受影响的行数 * @param note * @return */ public int addOrUpdate(Note note) { // 定义SQL语句 String sql = ""; // 设置参数 List params = new ArrayList(); params.add(note.getTypeId()); params.add(note.getTitle()); params.add(note.getContent()); // 判断noteId是否为空;如果为空,则为添加操作;如果不为空,则为修改操作 if (note.getNoteId() == null) { // 添加操作 sql = "insert into tb_note (typeId, title, content, pubTime, lon, lat) values (?,?,?,now(),?,?)"; params.add(note.getLon()); params.add(note.getLat()); } else { // 修改操作 sql = "update tb_note set typeId = ?, title = ? , content = ? where noteId = ?"; params.add(note.getNoteId()); } // 调用BaseDao的更新方法 int row = BaseDao.executeUpdate(sql, params); return row; } /** * 查询当前登录用户的云记数量,返回总记录数 * @param userId * @return */ public long findNoteCount(Integer userId, String title, String date, String typeId) { // 定义SQL语句 String sql = "SELECT count(1) FROM tb_note n INNER JOIN " + " tb_note_type t on n.typeId = t.typeId " + " WHERE userId = ? "; // 设置参数 List params = new ArrayList(); params.add(userId); // 判断条件查询的参数是否为空 (如果查询的参数不为空,则拼接sql语句,并设置所需要的参数) if (!StrUtil.isBlank(title)) { // 标题查询 // 拼接条件查询的sql语句 sql += " and title like concat('%',?,'%') "; // 设置sql语句所需要的参数 params.add(title); } else if (!StrUtil.isBlank(date)) { // 日期查询 // 拼接条件查询的sql语句 sql += " and date_format(pubTime,'%Y年%m月') = ? "; // 设置sql语句所需要的参数 params.add(date); } else if (!StrUtil.isBlank(typeId)) { // 类型查询 // 拼接条件查询的sql语句 sql += " and n.typeId = ? "; // 设置sql语句所需要的参数 params.add(typeId); } // 调用BaseDao的查询方法 long count = (long) BaseDao.findSingleValue(sql, params); return count; } /** * 分页查询当前登录用户下当前页的数据列表,返回note集合 * @param userId * @param index * @param pageSize * @return */ public List findNoteListByPage(Integer userId, Integer index, Integer pageSize, String title, String date, String typeId) { // 定义SQL语句 String sql = "SELECT noteId,title,pubTime FROM tb_note n INNER JOIN " + "tb_note_type t on n.typeId = t.typeId WHERE userId = ? "; // 设置参数 List params = new ArrayList(); params.add(userId); // 判断条件查询的参数是否为空 (如果查询的参数不为空,则拼接sql语句,并设置所需要的参数) if (!StrUtil.isBlank(title)) { // 拼接条件查询的sql语句 sql += " and title like concat('%',?,'%') "; // 设置sql语句所需要的参数 params.add(title); } else if (!StrUtil.isBlank(date)) { // 日期查询 // 拼接条件查询的sql语句 sql += " and date_format(pubTime,'%Y年%m月') = ? "; // 设置sql语句所需要的参数 params.add(date); } else if (!StrUtil.isBlank(typeId)) { // 类型查询 // 拼接条件查询的sql语句 sql += " and n.typeId = ? "; // 设置sql语句所需要的参数 params.add(typeId); } // 拼接分页的sql语句 (limit语句需要写在sql语句最后) sql += " order by pubTime desc limit ?,?"; params.add(index); params.add(pageSize); // 调用BaseDao的查询方法 List noteList = BaseDao.queryRows(sql, params, Note.class); return noteList; } /** * 通过日期分组查询当前登录用户下的云记数量 * @param userId * @return */ public List findNoteCountByDate(Integer userId) { // 定义SQL语句 String sql = "SELECT count(1) noteCount,DATE_FORMAT(pubTime,'%Y年%m月') groupName FROM tb_note n " + " INNER JOIN tb_note_type t ON n.typeId = t.typeId WHERE userId = ? " + " GROUP BY DATE_FORMAT(pubTime,'%Y年%m月')" + " ORDER BY DATE_FORMAT(pubTime,'%Y年%m月') DESC "; // 设置参数 List params = new ArrayList(); params.add(userId); // 调用BaseDao的查询方法 List list = BaseDao.queryRows(sql, params, NoteVo.class); return list; } /** * 通过类型分组查询当前登录用户下的云记数量 * @param userId * @return */ public List findNoteCountByType(Integer userId) { // 定义SQL语句 String sql = "SELECT count(noteId) noteCount, t.typeId, typeName groupName FROM tb_note n " + " RIGHT JOIN tb_note_type t ON n.typeId = t.typeId WHERE userId = ? " + " GROUP BY t.typeId ORDER BY COUNT(noteId) DESC "; // 设置参数 List params = new ArrayList(); params.add(userId); // 调用BaseDao的查询方法 List list = BaseDao.queryRows(sql, params, NoteVo.class); return list; } /** * 通过id查询云记对象 * @param noteId * @return */ public Note findNoteById(String noteId) { // 定义SQL String sql = "select noteId,title,content,pubTime,typeName,n.typeId from tb_note n " + " inner join tb_note_type t on n.typeId=t.typeId where noteId = ?"; // 设置参数 List params = new ArrayList(); params.add(noteId); // 调用BaseDao的查询方法 Note note = (Note) BaseDao.queryRow(sql, params, Note.class); return note; } /** * 通过noteId删除云记记录,返回受影响的行数 * @param noteId * @return */ public int deleteNoteById(String noteId) { String sql = "delete from tb_note where noteId= ?"; // 设置参数 List params = new ArrayList(); params.add(noteId); // 调用BaseDao int row = BaseDao.executeUpdate(sql, params); return row; } /** * 通过用户ID查询云记列表 * @param userId * @return */ public List queryNoteList(Integer userId) { // 定义SQL语句 String sql = "select lon, lat from tb_note n inner join tb_note_type t on n.typeId = t.typeId where userId = ?"; // 设置参数 List params = new ArrayList(); params.add(userId); // 调用BaseDao List list = BaseDao.queryRows(sql, params, Note.class); return list; }}
- NoteTypeDao
package com.lezijie.note.dao;import com.lezijie.note.po.NoteType;import com.lezijie.note.util.DBUtil;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.Statement;import java.util.ArrayList;import java.util.List;public class NoteTypeDao { /** * 通过用户ID查询类型集合 1. 定义SQL语句 String sql = "select typeId,typeName,userId from tb_note_type where userId = ? "; 2. 设置参数列表 3. 调用BaseDao的查询方法,返回集合 4. 返回集合 * @param userId * @return */ public List findTypeListByUserId(Integer userId) { // 1. 定义SQL语句 String sql = "select typeId,typeName,userId from tb_note_type where userId = ? "; // 2. 设置参数列表 List params = new ArrayList(); params.add(userId); // 3. 调用BaseDao的查询方法,返回集合 List list = BaseDao.queryRows(sql, params, NoteType.class); // 4. 返回集合 return list; } /** * 通过类型ID查询云记记录的数量,返回云记数量 * * @param typeId * @return */ public long findNoteCountByTypeId(String typeId) { // 定义SQL语句 String sql = "select count(1) from tb_note where typeId = ?"; // 设置参数集合 List params = new ArrayList(); params.add(typeId); // 调用BaseDao long count = (long) BaseDao.findSingleValue(sql, params); return count; } /** * 通过类型ID删除指定的类型记录,返回受影响的行数 * @param typeId * @return */ public int deleteTypeById(String typeId) { // 定义SQL语句 String sql = "delete from tb_note_type where typeId = ?"; // 设置参数集合 List params = new ArrayList(); params.add(typeId); // 调用BaseDao int row = BaseDao.executeUpdate(sql, params); return row; } /** * 查询当前登录用户下,类型名称是否唯一 * 返回1,表示成功 * 返回0,表示失败 * @param typeName * @param userId * @param typeId * @return */ public Integer checkTypeName(String typeName, Integer userId, String typeId) { // 定义SQL语句 String sql = "select * from tb_note_type where userId = ? and typeName = ?"; // 设置参数 List params = new ArrayList(); params.add(userId); params.add(typeName); // 执行查询操作 NoteType noteType = (NoteType) BaseDao.queryRow(sql, params, NoteType.class); // 如果对象为空,表示可用 if (noteType == null) { return 1; } else { // 如果是修改操作,则需要判断是否是当前记录本身 if (typeId.equals(noteType.getTypeId().toString())) { return 1; } } return 0; } /** * 添加方法,返回主键 * @param typeName * @param userId * @return */ public Integer addType(String typeName, Integer userId) { Integer key = null; Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 得到数据库连接 connection = DBUtil.getConnetion(); // 定义SQL语句 String sql = "insert into tb_note_type (typeName,userId) values (?,?)"; // 预编译 preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); // 设置参数 preparedStatement.setString(1,typeName); preparedStatement.setInt(2, userId); // 执行更新,返回受影响的行数 int row = preparedStatement.executeUpdate(); // 判断受影响的行数 if (row > 0) { // 获取返回主键的结果集 resultSet = preparedStatement.getGeneratedKeys(); // 得到主键的值 if (resultSet.next()) { key = resultSet.getInt(1); } } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭资源 DBUtil.close(resultSet,preparedStatement,connection); } return key; } /** * 修改方法,返回受影响的行数 * @param typeName * @param typeId * @return */ public Integer updateType(String typeName, String typeId) { // 定义SQL语句 String sql = "update tb_note_type set typeName = ? where typeId = ?"; // 设置参数 List params = new ArrayList(); params.add(typeName); params.add(typeId); // 调用BaseDao的更新方法 int row = BaseDao.executeUpdate(sql, params); return row; }}
- UserDao
package com.lezijie.note.dao;import com.lezijie.note.po.User;import com.lezijie.note.util.DBUtil;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;public class UserDao { /** * 通过用户名查询用户对象 * 1. 定义sql语句 * 2. 设置参数集合 * 3. 调用BaseDao的查询方法 * @param userName * @return */ public User queryUserByName(String userName) { // 1. 定义sql语句 String sql = "select * from tb_user where uname = ?"; // 2. 设置参数集合 List params = new ArrayList(); params.add(userName); // 3. 调用BaseDao的查询方法 User user = (User) BaseDao.queryRow(sql, params, User.class); return user; } /** 通过用户名查询用户对象, 返回用户对象 1. 获取数据库连接 2. 定义sql语句 3. 预编译 4. 设置参数 5. 执行查询,返回结果集 6. 判断并分析结果集 7. 关闭资源 * @param userName * @return */ public User queryUserByName02(String userName) { User user = null; Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 1. 获取数据库连接 connection = DBUtil.getConnetion(); // 2. 定义sql语句 String sql = "select * from tb_user where uname = ?"; // 3. 预编译 preparedStatement = connection.prepareStatement(sql); // 4. 设置参数 preparedStatement.setString(1, userName); // 5. 执行查询,返回结果集 resultSet = preparedStatement.executeQuery(); // 6. 判断并分析结果集 if (resultSet.next()) { user = new User(); user.setUserId(resultSet.getInt("userId")); user.setUname(userName); user.setHead(resultSet.getString("head")); user.setMood(resultSet.getString("mood")); user.setNick(resultSet.getString("nick")); user.setUpwd(resultSet.getString("upwd")); } } catch (Exception e) { e.printStackTrace(); } finally { // 7. 关闭资源 DBUtil.close(resultSet,preparedStatement,connection); }return user; } /** * 通过昵称与用户ID查询用户对象 * 1. 定义SQL语句 * 通过用户ID查询除了当前登录用户之外是否有其他用户使用了该昵称 * 指定昵称 nick (前台传递的参数) * 当前用户 userId (session作用域中的user对象) * String sql = "select * from tb_user where nick = ? and userId != ?"; * 2. 设置参数集合 * 3. 调用BaseDao的查询方法 * @param nick * @param userId * @return */ public User queryUserByNickAndUserId(String nick, Integer userId) { // 1. 定义SQL语句 String sql = "select * from tb_user where nick = ? and userId != ?"; // 2. 设置参数集合 List params = new ArrayList(); params.add(nick); params.add(userId); // 3. 调用BaseDao的查询方法 User user = (User) BaseDao.queryRow(sql, params, User.class); return user; } /** * 通过用户ID修改用户信息 1. 定义SQL语句 String sql = "update tb_user set nick = ?, mood = ?, head = ? where userId = ? "; 2. 设置参数集合 3. 调用BaseDao的更新方法,返回受影响的行数 4. 返回受影响的行数 * @param user * @return */ public int updateUser(User user) { // 1. 定义SQL语句 String sql = "update tb_user set nick = ?, mood = ?, head = ? where userId = ? "; // 2. 设置参数集合 List params = new ArrayList(); params.add(user.getNick()); params.add(user.getMood()); params.add(user.getHead()); params.add(user.getUserId()); // 3. 调用BaseDao的更新方法,返回受影响的行数 int row = BaseDao.executeUpdate(sql, params); return row; }}
9.1.2 filter层
- EncodingFilter
package com.lezijie.note.filter;import cn.hutool.core.util.StrUtil;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * * 字符乱码处理过滤器 * * 请求乱码解决 乱码原因: 服务器默认的解析编码为ISO-8859-1,不支持中文。 乱码情况: POST请求 Tomcat7及以下版本 乱码 Tomcat8及以上版本 乱码 GET请求 Tomcat7及以下版本 乱码 Tomcat8及以上版本 不乱码 解决方案: POST请求: 无论是什么版本的服务器,都会出现乱码,需要通过request.setCharacterEncoding("UTF-8")设置编码格式。(只针对POST请求有效) GET请求 Tomcat8及以上版本,不会乱码,不需要处理。 Tomcat7及以下版本,需要单独处理。 new String(request.getParamater("xxx").getBytes("ISO-8859-1"),"UTF-8"); */@WebFilter("/*") // 过滤所有资源public class EncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 基于HTTP HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 处理POST请求 (只针对POST请求有效,GET请求不受影响) request.setCharacterEncoding("UTF-8"); // 得到请求类型 (GET|POST) String method = request.getMethod(); // 如果是GET请求,则判断服务器版本 if ("GET".equalsIgnoreCase(method)) { // 忽略大小写比较 // 得到服务器版本 String serverInfo = request.getServletContext().getServerInfo(); // Apache Tomcat/7.0.79 // 通过截取字符串,得到具体的版本号 String version = serverInfo.substring(serverInfo.lastIndexOf("/")+1,serverInfo.indexOf(".")); // 判断服务器版本是否是Toncat7级以下 if (version != null && Integer.parseInt(version) < 8) { // Tomcat7及以下版本的服务器的GET请求 MyWapper myRequest = new MyWapper(request); // 放行资源 filterChain.doFilter(myRequest, response); return; } } filterChain.doFilter(request,response); } /** * 1. 定义内部类 (类的本质是request对象) * 2. 继承 HttpServletRequestWrapper包装类 * 3. 重写getarameterP()方法 */ class MyWapper extends HttpServletRequestWrapper { // 定义成员变量 HttpServletRequest对象 (提升构造器中request对象的作用域) private HttpServletRequest request; /** * 带参构造 * 可以得到需要处理的request对象 * @param request */ public MyWapper(HttpServletRequest request) { super(request); this.request = request; } /** * 重写getParameter方法,处理乱码问题 * @param name * @return */ @Override public String getParameter(String name) { // 获取参数 (乱码的参数值) String value = request.getParameter(name); // 判断参数值是否为空 if (StrUtil.isBlank(value)) { return value; } // 通过new String()处理乱码 try { value = new String(value.getBytes("ISO-8859-1"), "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return value; } }}
- LoginAccessFilter
package com.lezijie.note.filter;import com.lezijie.note.po.User;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * 非法访问拦截 * 拦截的资源: * 所有的资源 /* * * 需要被放行的资源 * 1. 指定页面,放行 (用户无需登录的即可访问的页面;例如:登录页面login.jsp、注册页面register.jsp等) * 2. 静态资源,放行 (存放在statics目录下的资源;例如:js、css、images等) * 3. 指定行为,放行 (用户无需登录即可执行的操作;例如:登录操作actionName=login等) * 4. 登录状态,放行 (判断session作用域中是否存在user对象;存在则放行,不存在,则拦截跳转到登录页面) *
* 免登录(自动登录) * 通过Cookie和Session对象实现 *
* 什么时候使用免登录: * 当用户处于未登录状态,且去请求需要登录才能访问的资源时,调用自动登录功能 *
* 目的: * 让用户处于登录状态(自动调用登录方法) *
* 实现: * 从Cookie对象中获取用户的姓名与密码,自动执行登录操作 * 1. 获取Cookie数组 request.getCookies() * 2. 判断Cookie数组 * 3. 遍历Cookie数组,获取指定的Cookie对象 (name为user的cookie对象) * 4. 得到对应的cookie对象的value (姓名与密码:userName-userPwd) * 5. 通过split()方法将value字符串分割成数组 * 6. 从数组中分别得到对应的姓名与密码值 * 7. 请求转发到登录操作 user?actionName=login&userName=姓名&userPwd=密码 * 8. return *
* 如果以上判断都不满足,则拦截跳转到登录页面 */@WebFilter("/*")public class LoginAccessFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // 基于HTTP HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 得到访问的路径 String path = request.getRequestURI(); // 格式:项目路径/资源路径 // 1. 指定页面,放行 (用户无需登录的即可访问的页面;例如:登录页面login.jsp、注册页面register.jsp等) if (path.contains("/login.jsp")) { filterChain.doFilter(request, response); return; } // 2. 静态资源,放行 (存放在statics目录下的资源;例如:js、css、images等) if (path.contains("/statics")) { filterChain.doFilter(request, response); return; } // 3. 指定行为,放行 (用户无需登录即可执行的操作;例如:登录操作actionName=login等) if (path.contains("/user")) { // 得到用户行为 String actionName = request.getParameter("actionName"); // 判断是否是登录操作 if ("login".equals(actionName)) { filterChain.doFilter(request, response); return; } } // 4. 登录状态,放行 (判断session作用域中是否存在user对象;存在则放行,不存在,则拦截跳转到登录页面) // 获取Session作用域中的user对象 User user = (User) request.getSession().getAttribute("user"); // 判断user对象是否为空 if (user != null) { filterChain.doFilter(request, response); return; } /** * 免登录 (自动登录) * 从Cookie对象中获取用户的姓名与密码,自动执行登录操作 */ // 1. 获取Cookie数组 request.getCookies() Cookie[] cookies = request.getCookies(); // 2. 判断Cookie数组 if (cookies != null && cookies.length > 0) { // 3. 遍历Cookie数组,获取指定的Cookie对象 (name为user的cookie对象) for (Cookie cookie : cookies) { if ("user".equals(cookie.getName())) { // 4. 得到对应的cookie对象的value (姓名与密码:userName-userPwd) String value = cookie.getValue(); // admin-123456 // 5. 通过split()方法将value字符串分割成数组 String[] val = value.split("-"); // 6. 从数组中分别得到对应的姓名与密码值 String userName = val[0]; String userPwd = val[1]; // 7. 请求转发到登录操作 user?actionName=login&userName=姓名&userPwd=密码 String url = "user?actionName=login&rem=1&userName=" + userName + "&userPwd=" + userPwd; request.getRequestDispatcher(url).forward(request, response); // 8. return return; } } } // 拦截请求,重定向跳转到登录页面 response.sendRedirect("login.jsp"); } @Override public void destroy() { }}
9.1.3 po层
- Note
package com.lezijie.note.po;import lombok.Getter;import lombok.Setter;import java.util.Date;@Getter@Setterpublic class Note { private Integer noteId; // 云记ID private String title; // 云记标题 private String content; // 云记内容 private Integer typeId; // 云记类型ID private Date pubTime; // 发布时间 private Float lon; // 经度 private Float lat; // 纬度 private String typeName;}
- NoteType
package com.lezijie.note.po;import lombok.Getter;import lombok.Setter;@Getter@Setterpublic class NoteType { private Integer typeId; // 类型ID private String typeName; // 类型名称 private Integer userId; // 用户ID}
- User
package com.lezijie.note.po;import lombok.Getter;import lombok.Setter;@Getter@Setterpublic class User { private Integer userId; // 用户ID private String uname; // 用户名称 private String upwd; // 用户密码 private String nick; // 用户昵称 private String head; // 用户头像 private String mood; // 用户签名 public void setUserId(Integer userId) { this.userId = userId; }}
9.1.4 service层
- NoteService
package com.lezijie.note.service;import cn.hutool.core.util.StrUtil;import com.lezijie.note.dao.NoteDao;import com.lezijie.note.po.Note;import com.lezijie.note.util.Page;import com.lezijie.note.vo.NoteVo;import com.lezijie.note.vo.ResultInfo;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class NoteService { private NoteDao noteDao = new NoteDao(); /** * 添加或修改云记 1. 参数的非空判断 如果为空,code=0,msg=xxx,result=note对象,返回resultInfo对象 2. 设置回显对象 Note对象 3. 调用Dao层,添加云记记录,返回受影响的行数 4. 判断受影响的行数 如果大于0,code=1 如果不大于0,code=0,msg=xxx,result=note对象 5. 返回resultInfo对象 * @param typeId * @param title * @param content * @return */ public ResultInfo addOrUpdate(String typeId, String title, String content, String noteId, String lon, String lat) { ResultInfo resultInfo = new ResultInfo(); // 1. 参数的非空判断 if (StrUtil.isBlank(typeId)) { resultInfo.setCode(0); resultInfo.setMsg("请选择云记类型!"); return resultInfo; } if (StrUtil.isBlank(title)) { resultInfo.setCode(0); resultInfo.setMsg("云记标题不能为空!"); return resultInfo; } if (StrUtil.isBlank(content)) { resultInfo.setCode(0); resultInfo.setMsg("云记内容不能为空!"); return resultInfo; } // 设置经纬度的默认,默认设置为北京 116.404, 39.915 if (lon == null || lat == null) { lon = "116.404"; lat = "39.915"; } // 2. 设置回显对象 Note对象 Note note = new Note(); note.setTitle(title); note.setContent(content); note.setTypeId(Integer.parseInt(typeId)); note.setLon(Float.parseFloat(lon)); note.setLat(Float.parseFloat(lat)); // 判断云记ID是否为空 if (!StrUtil.isBlank(noteId)) { note.setNoteId(Integer.parseInt(noteId)); } resultInfo.setResult(note); // 3. 调用Dao层,添加云记记录,返回受影响的行数 int row = noteDao.addOrUpdate(note); // 4. 判断受影响的行数 if (row > 0) { resultInfo.setCode(1); } else { resultInfo.setCode(0); resultInfo.setResult(note); resultInfo.setMsg("更新失败!"); } return resultInfo; } /** * 分页查询云记列表 1. 参数的非空校验 如果分页参数为空,则设置默认值 2. 查询当前登录用户的云记数量,返回总记录数 (long类型) 3. 判断总记录数是否大于0 4. 如果总记录数大于0,调用Page类的带参构造,得到其他分页参数的值,返回Page对象 5. 查询当前登录用户下当前页的数据列表,返回note集合 6. 将note集合设置到page对象中 7. 返回Page对象 * @param pageNumStr * @param pageSizeStr * @param userId * @param title 条件查询的参数:标题 * @return */ public Page findNoteListByPage(String pageNumStr, String pageSizeStr, Integer userId, String title, String date, String typeId) { // 设置分页参数的默认值 Integer pageNum = 1; // 默认当前页是第一页 Integer pageSize = 5; // 默认每页显示5条数据 // 1. 参数的非空校验 (如果参数不为空,则设置参数) if (!StrUtil.isBlank(pageNumStr)) { // 设置当前页 pageNum = Integer.parseInt(pageNumStr); } if (!StrUtil.isBlank(pageSizeStr)) { // 设置每页显示的数量 pageSize = Integer.parseInt(pageSizeStr); } // 2. 查询当前登录用户的云记数量,返回总记录数 (long类型) long count = noteDao.findNoteCount(userId, title, date, typeId); // 3. 判断总记录数是否大于0 if (count < 1) { return null; } // 4. 如果总记录数大于0,调用Page类的带参构造,得到其他分页参数的值,返回Page对象 Page page = new Page(pageNum, pageSize, count); // 得到数据库中分页查询的开始下标 Integer index = (pageNum -1) * pageSize; // 5. 查询当前登录用户下当前页的数据列表,返回note集合 List noteList = noteDao.findNoteListByPage(userId, index, pageSize, title, date, typeId); // 6. 将note集合设置到page对象中 page.setDataList(noteList); // 7. 返回Page对象 return page; } /** * 通过日期分组查询当前登录用户下的云记数量 * @param userId * @return */ public List findNoteCountByDate(Integer userId) { return noteDao.findNoteCountByDate(userId); } /** * 通过类型分组查询当前登录用户下的云记数量 * @param userId * @return */ public List findNoteCountByType(Integer userId) { return noteDao.findNoteCountByType(userId); } /** * 查询云记详情 1. 参数的非空判断 2. 调用Dao层的查询,通过noteId查询note对象 3. 返回note对象 * @param noteId * @return */ public Note findNoteById(String noteId) { // 1. 参数的非空判断 if (StrUtil.isBlank(noteId)) { return null; } // 2. 调用Dao层的查询,通过noteId查询note对象 Note note = noteDao.findNoteById(noteId); // 3. 返回note对象 return note; } /** * 删除云记 1. 判断参数 2. 调用Dao层的更新方法,返回受影响的行数 3. 判断受影响的行数是否大于0 如果大于0,返回1;否则返回0 * @param noteId * @return */ public Integer deleteNote(String noteId) { // 1. 判断参数 if (StrUtil.isBlank(noteId)) { return 0; } // 2. 调用Dao层的更新方法,返回受影响的行数 int row = noteDao.deleteNoteById(noteId); // 3. 判断受影响的行数是否大于0 if (row > 0) { return 1; } return 0; } /** * 通过月份查询对应的云记数量 * @param userId * @return */ public ResultInfo<Map> queryNoteCountByMonth(Integer userId) { ResultInfo<Map> resultInfo = new ResultInfo(); // 通过月份分类查询云记数量 List noteVos = noteDao.findNoteCountByDate(userId); // 判断集合是否存在 if (noteVos != null && noteVos.size() > 0) { // 得到月份 List monthList = new ArrayList(); // 得到云记集合 List noteCountList = new ArrayList(); // 遍历月份分组集合 for (NoteVo noteVo: noteVos) { monthList.add(noteVo.getGroupName()); noteCountList.add((int)noteVo.getNoteCount()); } // 准备Map对象,封装对应的月份与云记数量 Map map = new HashMap(); map.put("monthArray", monthList); map.put("dataArray", noteCountList); // 将map对象设置到ResultInfo对象中 resultInfo.setCode(1); resultInfo.setResult(map); } return resultInfo; } /** * 查询用户发布云记时的坐标 * @param userId * @return */ public ResultInfo<List> queryNoteLonAndLat(Integer userId) { ResultInfo<List> resultInfo = new ResultInfo(); // 通过用户ID查询云记列表 List noteList = noteDao.queryNoteList(userId); // 判断是否为空 if (noteList != null && noteList.size() > 0) { resultInfo.setCode(1); resultInfo.setResult(noteList); } return resultInfo; }}
- NoteTypeService
package com.lezijie.note.service;import cn.hutool.core.util.StrUtil;import com.lezijie.note.dao.NoteTypeDao;import com.lezijie.note.po.NoteType;import com.lezijie.note.vo.ResultInfo;import java.util.List;public class NoteTypeService { private NoteTypeDao typeDao = new NoteTypeDao(); /** * 查询类型列表 1. 调用Dao层的查询方法,通过用户ID查询类型集合 2. 返回类型集合 * @param userId * @return */ public List findTypeList(Integer userId) { List typeList = typeDao.findTypeListByUserId(userId); return typeList; } /** * 删除类型 1. 判断参数是否为空 2. 调用Dao层,通过类型ID查询云记记录的数量 3. 如果云记数量大于0,说明存在子记录,不可删除 code=0,msg="该类型存在子记录,不可删除",返回resultInfo对象 4. 如果不存在子记录,调用Dao层的更新方法,通过类型ID删除指定的类型记录,返回受影响的行数 5. 判断受影响的行数是否大于0 大于0,code=1;否则,code=0,msg="删除失败" 6. 返回ResultInfo对象 * @param typeId * @return */ public ResultInfo deleteType(String typeId) { ResultInfo resultInfo = new ResultInfo(); // 1. 判断参数是否为空 if (StrUtil.isBlank(typeId)) { resultInfo.setCode(0); resultInfo.setMsg("系统异常,请重试!"); return resultInfo; } // 2. 调用Dao层,通过类型ID查询云记记录的数量 long noteCount = typeDao.findNoteCountByTypeId(typeId); // 3. 如果云记数量大于0,说明存在子记录,不可删除 if (noteCount > 0) { resultInfo.setCode(0); resultInfo.setMsg("该类型存在子记录,不可删除!!"); return resultInfo; } // 4. 如果不存在子记录,调用Dao层的更新方法,通过类型ID删除指定的类型记录,返回受影响的行数 int row = typeDao.deleteTypeById(typeId); // 5. 判断受影响的行数是否大于0 if (row > 0) { resultInfo.setCode(1); } else { resultInfo.setCode(0); resultInfo.setMsg("删除失败!"); } return resultInfo; } /** * 添加或修改类型 1. 判断参数是否为空 (类型名称) 如果为空,code=0,msg=xxx,返回ResultInfo对象 2. 调用Dao层,查询当前登录用户下,类型名称是否唯一,返回0或1 如果不可用,code=0,msg=xxx,返回ResultInfo对象 3. 判断类型ID是否为空 如果为空,调用Dao层的添加方法,返回主键 (前台页面需要显示添加成功之后的类型ID) 如果不为空,调用Dao层的修改方法,返回受影响的行数 4. 判断 主键/受影响的行数 是否大于0 如果大于0,则更新成功 code=1,result=主键 如果不大于0,则更新失败 code=0,msg=xxx * @param typeName * @param userId * @param typeId * @return */ public ResultInfo addOrUpdate(String typeName, Integer userId, String typeId) { ResultInfo resultInfo = new ResultInfo(); // 1. 判断参数是否为空 (类型名称) if (StrUtil.isBlank(typeName)) { resultInfo.setCode(0); resultInfo.setMsg("类型名称不能为空!"); return resultInfo; } // 2. 调用Dao层,查询当前登录用户下,类型名称是否唯一,返回0或1 (1=可用;0=不可用) Integer code = typeDao.checkTypeName(typeName, userId, typeId); // 如果不可用,code=0,msg=xxx,返回ResultInfo对象 if (code == 0) { resultInfo.setCode(0); resultInfo.setMsg("类型名称已存在,请重新输入!"); return resultInfo; } // 3. 判断类型ID是否为空 // 返回的结果 Integer key = null; // 主键或受影响的行数 if (StrUtil.isBlank(typeId)) { // 如果为空,调用Dao层的添加方法,返回主键 (前台页面需要显示添加成功之后的类型ID) key = typeDao.addType(typeName, userId); } else { // 如果不为空,调用Dao层的修改方法,返回受影响的行数 key = typeDao.updateType(typeName, typeId); } // 4. 判断 主键/受影响的行数 是否大于0 if (key > 0) { resultInfo.setCode(1); resultInfo.setResult(key); } else { resultInfo.setCode(0); resultInfo.setMsg("更新失败!"); } return resultInfo; }}
- UserService
package com.lezijie.note.service;import cn.hutool.core.util.StrUtil;import cn.hutool.crypto.digest.DigestUtil;import com.lezijie.note.dao.UserDao;import com.lezijie.note.po.User;import com.lezijie.note.vo.ResultInfo;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.Part;public class UserService { private UserDao userDao = new UserDao(); /** * 用户登录 1. 判断参数是否为空 如果为空 设置ResultInfo对象的状态码和提示信息 返回resultInfo对象 2. 如果不为空,通过用户名查询用户对象 3. 判断用户对象是否为空 如果为空 设置ResultInfo对象的状态码和提示信息 返回resultInfo对象 4. 如果用户对象不为空,将数据库中查询到的用户对象的密码与前台传递的密码作比较 (将密码加密后再比较) 如果密码不正确 设置ResultInfo对象的状态码和提示信息 返回resultInfo对象 5. 如果密码正确 设置ResultInfo对象的状态码和提示信息 6. 返回resultInfo对象 * @param userName * @param userPwd * @return */ public ResultInfo userLogin(String userName, String userPwd) { ResultInfo resultInfo = new ResultInfo(); // 数据回显:当登录实现时,将登录信息返回给页面显示 User u = new User(); u.setUname(userName); u.setUpwd(userPwd); // 设置到resultInfo对象中 resultInfo.setResult(u); // 1. 判断参数是否为空 if (StrUtil.isBlank(userName) || StrUtil.isBlank(userPwd)) { // 如果为空 设置ResultInfo对象的状态码和提示信息 resultInfo.setCode(0); resultInfo.setMsg("用户姓名或密码不能为空!"); // 返回resultInfo对象 return resultInfo; } // 2. 如果不为空,通过用户名查询用户对象 User user = userDao.queryUserByName(userName); // 3. 判断用户对象是否为空 if (user == null) { // 如果为空,设置ResultInfo对象的状态码和提示信息 resultInfo.setCode(0); resultInfo.setMsg("该用户不存在!"); // 返回resultInfo对象 return resultInfo; } // 4. 如果用户对象不为空,将数据库中查询到的用户对象的密码与前台传递的密码作比较 (将密码加密后再比较) // 将前台传递的密码按照MD5算法的方式加密 userPwd = DigestUtil.md5Hex(userPwd); // 判断加密后的密码是否与数据库中的一致 if (!userPwd.equals(user.getUpwd())) { // 如果密码不正确 resultInfo.setCode(0); resultInfo.setMsg("用户密码不正确!"); return resultInfo; } resultInfo.setCode(1); resultInfo.setResult(user); return resultInfo; } /** * 验证昵称的唯一性 * 1. 判断昵称是否为空 * 如果为空,返回"0" * 2. 调用Dao层,通过用户ID和昵称查询用户对象 * 3. 判断用户对象存在 * 存在,返回"0" * 不存在,返回"1" * @param nick * @param userId * @return */ public Integer checkNick(String nick, Integer userId) { // 1. 判断昵称是否为空 if (StrUtil.isBlank(nick)) { return 0; } // 2. 调用Dao层,通过用户ID和昵称查询用户对象 User user = userDao.queryUserByNickAndUserId(nick, userId); // 3. 判断用户对象存在 if (user != null) { return 0; } return 1; } /** * 修改用户信息 1. 获取参数(昵称、心情) 2. 参数的非空校验(判断必填参数非空) 如果昵称为空,将状态码和错误信息设置resultInfo对象中,返回resultInfo对象 3. 从session作用域中获取用户对象(获取用户对象中默认的头像) 4. 实现上上传文件 1. 获取Part对象 request.getPart("name"); name代表的是file文件域的那么属性值 2. 通过Part对象获取上传文件的文件名 3. 判断文件名是否为空 4. 获取文件存放的路径 WEB-INF/upload/目录中 5. 上传文件到指定目录 5. 更新用户头像 (将原本用户对象中的默认头像设置为上传的文件名) 6. 调用Dao层的更新方法,返回受影响的行数 7. 判断受影响的行数 如果大于0,则修改成功;否则修改失败 8. 返回resultInfo对象 * @param request * @return */ public ResultInfo updateUser(HttpServletRequest request) { ResultInfo resultInfo = new ResultInfo(); // 1. 获取参数(昵称、心情) String nick = request.getParameter("nick"); String mood = request.getParameter("mood"); // 2. 参数的非空校验(判断必填参数非空) if (StrUtil.isBlank(nick)) { // 如果昵称为空,将状态码和错误信息设置resultInfo对象中,返回resultInfo对象 resultInfo.setCode(0); resultInfo.setMsg("用户昵称不能卫空!"); return resultInfo; } // 3. 从session作用域中获取用户对象(获取用户对象中默认的头像) User user = (User) request.getSession().getAttribute("user"); // 设置修改的昵称和头像 user.setNick(nick); user.setMood(mood); // 4. 实现上上传文件 try { // 1. 获取Part对象 request.getPart("name"); name代表的是file文件域的name属性值 Part part = request.getPart("img"); // 2. 通过Part对象获取上传文件的文件名 (从头部信息中获取上传的文件名) String header = part.getHeader("Content-Disposition"); // 获取具体的请求头对应的值 String str = header.substring(header.lastIndexOf("=") + 2); // 获取上传的文件名 String fileName = str.substring(0, str.length() - 1); // 3. 判断文件名是否为空 if (!StrUtil.isBlank(fileName)) { // 如果用户上传了头像,则更新用户对象中的头像 user.setHead(fileName); // 4. 获取文件存放的路径 WEB-INF/upload/目录中 String filePath = request.getServletContext().getRealPath("/WEb-INF/upload/"); // 5. 上传文件到指定目录 part.write(filePath + "/" + fileName); } } catch (Exception e) { e.printStackTrace(); } // 6. 调用Dao层的更新方法,返回受影响的行数 int row = userDao.updateUser(user); // 7. 判断受影响的行数 if (row > 0) { resultInfo.setCode(1); // 更新session中用户对象 request.getSession().setAttribute("user", user); } else { resultInfo.setCode(0); resultInfo.setMsg("更新失败!"); } return resultInfo; }}
9.1.5 util层
- DBUtil
package com.lezijie.note.util;import java.io.InputStream;import java.sql.*;import java.util.Properties;/** * 乐字节:专注线上IT培训 * 需要视频资料,请添加:lezijie007 */public class DBUtil { // 得到配置文件对象 private static Properties properties = new Properties(); static { try { // 加载配置文件(输入流) InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db.properties"); // 通过load()方法将输入流的内容加载到配置文件对象中 properties.load(in); // 通过配置文件对象的getProperty()方法获取驱动名,并加载驱动 Class.forName(properties.getProperty("jdbcName")); } catch (Exception e) { e.printStackTrace(); } } /** * 获取数据库连接 * @return */ public static Connection getConnetion() { Connection connection = null; try { // 得到数据库连接的相关信息 String dbUrl = properties.getProperty("dbUrl"); String dbName = properties.getProperty("dbName"); String dbPwd = properties.getProperty("dbPwd"); // 得到数据库连接 connection = DriverManager.getConnection(dbUrl, dbName, dbPwd); } catch (SQLException throwables) { throwables.printStackTrace(); } return connection; } /** * 关闭资源 * @param resultSet * @param preparedStatement * @param connection */ public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) { try { // 判断资源对象如果不为空,则关闭 if (resultSet != null) { resultSet.close(); } if (preparedStatement != null) { preparedStatement.close(); } if (connection != null) { connection.close(); } } catch (Exception e) { e.printStackTrace(); } }}
- JsonUtil
package com.lezijie.note.util;import com.alibaba.fastjson.JSON;import javax.servlet.http.HttpServletResponse;import java.io.PrintWriter;/** * 将对象转换成JOSN格式的字符串,响应给ajax的回调函数 */public class JsonUtil { public static void toJson(HttpServletResponse response, Object result) { try { // 设置响应类型及编码格式 (json类型) response.setContentType("application/json;charset=UTF-8"); // 得到字符输出流 PrintWriter out = response.getWriter(); // 通过fastjson的方法,将ResultInfo对象转换成JSON格式的字符串 String json = JSON.toJSONString(result); // 通过输出流输出JSON格式的字符串 out.write(json); // 关闭资源 out.close(); } catch (Exception e) { e.printStackTrace(); } }}
- Page
package com.lezijie.note.util;import lombok.Getter;import lombok.Setter;import java.util.List;/** * 分页工具类 */@Getter@Setterpublic class Page { private Integer pageNum; // 当前页 (前台传递的参数;如果前台未传递,则默认第一页) private Integer pageSize; // 每页显示的数量 (前台传递或后台设定) private long totalCount; // 总记录数 (后台数据库中查询得到;count()函数) private Integer totalPages; // 总页数 (总记录数/每页显示的数量;将参数转换为浮点型,执行除法操作,向上取整) private Integer prePage; // 上一页 (当前页-1;如果当前页-1小于1,则上一页为1) private Integer nextPage; // 下一页 (当前页+1;如果当前页+1大于总页数,则下一页为总页数的值) private Integer startNavPage; // 导航开始页 (当前页-5;如果当前页-5小于1,则导航开始页为1,此时导航结束页为导航开始数+9;如果导航开始数+9大于总页数,则导航结束页为总页数) private Integer endNavPage; // 导航结束页 (当前页+4;如果当前页+4大于总页数,则导航结束页为总页数,此时导航开始页为导航结束页-9;如果导航结束页-9小于1,则导航开始页为1) private List dataList; // 当前页的数据集合 (查询数据库中指定页的数据列表) /** * 带参构造 * 通过指定参数,得到其他分页参数的值 * @param pageNum * @param pageSize * @param totalCount */ public Page(Integer pageNum, Integer pageSize, long totalCount) { this.pageNum = pageNum; this.pageSize = pageSize; this.totalCount = totalCount; // 总页数 (总记录数/每页显示的数量;将参数转换为浮点型,执行除法操作,向上取整) this.totalPages = (int)Math.ceil(totalCount/(pageSize * 1.0)); // 上一页 (当前页-1;如果当前页-1小于1,则上一页为1) this.prePage = pageNum - 1 totalPages ? totalPages : pageNum + 1; this.startNavPage = pageNum - 5; // 导航开始页 (当前页-5) this.endNavPage = pageNum + 4; // 导航结束页 (当前页+4) // 导航开始页 (当前页-5;如果当前页-5小于1,则导航开始页为1,此时导航结束页为导航开始数+9;如果导航开始数+9大于总页数,则导航结束页为总页数) if (this.startNavPage totalPages ? totalPages : this.startNavPage + 9; } // 导航结束页 (当前页+4;如果当前页+4大于总页数,则导航结束页为总页数,此时导航开始页为导航结束页-9;如果导航结束页-9小于1,则导航开始页为1) if (this.endNavPage > totalPages) { // 如果当前页+4大于总页数,则导航结束页为总页数 this.endNavPage = totalPages; // 此时导航开始页为导航结束页-9;如果导航结束页-9小于1,则导航开始页为1 this.startNavPage = this.endNavPage - 9 < 1 ? 1 : this.endNavPage - 9; } }}
9.1.6 vo层
- NoteVo
package com.lezijie.note.vo;import lombok.Getter;import lombok.Setter;@Getter@Setterpublic class NoteVo { private String groupName; // 分组名称 private long noteCount; // 云记数量 private Integer typeId; // 类型ID}
- ResultInfo
package com.lezijie.note.vo;import lombok.Getter;import lombok.Setter;/** * 封装返回结果的类 * 状态码 * 成功=1,失败=0 * 提示信息 * 返回的对象(字符串、JavaBean、集合、Map等) */@Getter@Setterpublic class ResultInfo { private Integer code; // 状态码 成功=1,失败=0 private String msg; // 提示信息 private T result; // 返回的对象(字符串、JavaBean、集合、Map等)}
9.1.7 web层
- IndexServlet
package com.lezijie.note.web;import com.lezijie.note.po.Note;import com.lezijie.note.po.User;import com.lezijie.note.service.NoteService;import com.lezijie.note.util.Page;import com.lezijie.note.vo.NoteVo;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;@WebServlet("/index")public class IndexServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置首页导航高亮 request.setAttribute("menu_page", "index"); // 得到用户行为 (判断是什么条件查询:标题查询、日期查询、类型查询) String actionName = request.getParameter("actionName"); // 将用户行为设置到request作用域中 (分页导航中需要获取) request.setAttribute("action", actionName); // 判断用户行为 if ("searchTitle".equals(actionName)) { // 标题查询 // 得到查询条件:标题 String title = request.getParameter("title"); // 将查询条件设置到request请求域中(查询条件的回显) request.setAttribute("title", title); // 标题搜索 noteList(request, response, title, null, null); } else if ("searchDate".equals(actionName)) { // 日期查询 // 得到查询条件:日期 String date = request.getParameter("date"); // 将查询条件设置到request请求域中(查询条件的回显) request.setAttribute("date", date); // 日期搜索 noteList(request, response, null, date, null); } else if ("searchType".equals(actionName)) { // 类型查询 // 得到查询条件:类型ID String typeId = request.getParameter("typeId"); // 将查询条件设置到request请求域中(查询条件的回显) request.setAttribute("typeId", typeId); // 日期搜索 noteList(request, response, null, null, typeId); } else { // 分页查询云记列表 noteList(request, response, null, null, null); } // 设置首页动态包含的页面 request.setAttribute("changePage","note/list.jsp"); // 请求转发到index.jsp request.getRequestDispatcher("index.jsp").forward(request, response); } /** * 分页查询云记列表 1. 接收参数 (当前页、每页显示的数量) 2. 获取Session作用域中的user对象 3. 调用Service层查询方法,返回Page对象 4. 将page对象设置到request作用域中 * @param request * @param response * @param title 标题 */ private void noteList(HttpServletRequest request, HttpServletResponse response, String title, String date, String typeId) { // 1. 接收参数 (当前页、每页显示的数量) String pageNum = request.getParameter("pageNum"); String pageSize = request.getParameter("pageSize"); // 2. 获取Session作用域中的user对象 User user = (User) request.getSession().getAttribute("user"); // 3. 调用Service层查询方法,返回Page对象 Page page = new NoteService().findNoteListByPage(pageNum, pageSize, user.getUserId(), title, date, typeId); // 4. 将page对象设置到request作用域中 request.setAttribute("page", page); // 通过日期分组查询当前登录用户下的云记数量 List dateInfo = new NoteService().findNoteCountByDate(user.getUserId()); // 设置集合存放在request作用域中 request.getSession().setAttribute("dateInfo", dateInfo); // 通过类型分组查询当前登录用户下的云记数量 List typeInfo = new NoteService().findNoteCountByType(user.getUserId()); // 设置集合存放在request作用域中 request.getSession().setAttribute("typeInfo", typeInfo); }}
- NoteServlet
package com.lezijie.note.web;import cn.hutool.core.util.StrUtil;import com.lezijie.note.po.Note;import com.lezijie.note.po.NoteType;import com.lezijie.note.po.User;import com.lezijie.note.service.NoteService;import com.lezijie.note.service.NoteTypeService;import com.lezijie.note.vo.ResultInfo;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;@WebServlet("/note")public class NoteServlet extends HttpServlet { private NoteService noteService = new NoteService(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置首页导航栏的高亮值 request.setAttribute("menu_page", "note"); // 得到用户行为 String actionName = request.getParameter("actionName"); // 判断用户行为 if ("view".equals(actionName)) { // 进入发布云记页面 noteView(request, response); } else if ("addOrUpdate".equals(actionName)) { // 添加或修改云记 addOrUpdate(request, response); } else if ("detail".equals(actionName)) { // 查询云记详情 noteDetail(request, response); } else if ("delete".equals(actionName)) { // 删除云记 noteDelete(request, response); } } /** * 删除云记 1. 接收参数 (noteId) 2. 调用Service层删除方法,返回状态码 (1=成功,0=失败) 3. 通过流将结果响应给ajax的回调函数 (输出字符串) * @param request * @param response */ private void noteDelete(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 接收参数 (noteId) String noteId = request.getParameter("noteId"); // 2. 调用Service层删除方法,返回状态码 (1=成功,0=失败) Integer code = noteService.deleteNote(noteId); // 3. 通过流将结果响应给ajax的回调函数 (输出字符串) response.getWriter().write(code + ""); response.getWriter().close(); } /** * 查询云记详情 1. 接收参数 (noteId) 2. 调用Service层的查询方法,返回Note对象 3. 将Note对象设置到request请求域中 4. 设置首页动态包含的页面值 5. 请求转发跳转到index.jsp * @param request * @param response */ private void noteDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 接收参数 (noteId) String noteId = request.getParameter("noteId"); // 2. 调用Service层的查询方法,返回Note对象 Note note = noteService.findNoteById(noteId); // 3. 将Note对象设置到request请求域中 request.setAttribute("note", note); // 4. 设置首页动态包含的页面值 request.setAttribute("changePage","note/detail.jsp"); // 5. 请求转发跳转到index.jsp request.getRequestDispatcher("index.jsp").forward(request, response); } /** * 添加或修改操作 1. 接收参数 (类型ID、标题、内容) 2. 调用Service层方法,返回resultInfo对象 3. 判断resultInfo的code值 如果code=1,表示成功 重定向跳转到首页 index 如果code=0,表示失败 将resultInfo对象设置到request作用域 请求转发跳转到note?actionName=view * @param request * @param response */ private void addOrUpdate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // 1. 接收参数 (类型ID、标题、内容) String typeId = request.getParameter("typeId"); String title = request.getParameter("title"); String content = request.getParameter("content"); // 获取经纬度 String lon = request.getParameter("lon"); String lat = request.getParameter("lat"); // 如果是修改操作,需要接收noteId String noteId = request.getParameter("noteId"); // 2. 调用Service层方法,返回resultInfo对 ResultInfo resultInfo = noteService.addOrUpdate(typeId, title, content, noteId, lon, lat); // 3. 判断resultInfo的code值 if (resultInfo.getCode() == 1) { // 重定向跳转到首页 index response.sendRedirect("index"); } else { // 将resultInfo对象设置到request作用域 request.setAttribute("resultInfo", resultInfo); // 请求转发跳转到note?actionName=view String url = "note?actionName=view"; // 如果是修改操作,需要传递noteId if (!StrUtil.isBlank(noteId)) { url += "¬eId="+noteId; } request.getRequestDispatcher(url).forward(request, response); } } /** * 进入发布云记页面 1. 从Session对象中获取用户对象 2. 通过用户ID查询对应的类型列表 3. 将类型列表设置到request请求域中 4. 设置首页动态包含的页面值 5. 请求转发跳转到index.jsp * @param request * @param response */ private void noteView(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* 修改操作 */ // 得到要修改的云记ID String noteId = request.getParameter("noteId"); // 通过noteId查询云记对象 Note note = noteService.findNoteById(noteId); // 将note对象设置到请求域中 request.setAttribute("noteInfo", note); /* 修改操作 */ // 1. 从Session对象中获取用户对象 User user = (User) request.getSession().getAttribute("user"); // 2. 通过用户ID查询对应的类型列表 List typeList = new NoteTypeService().findTypeList(user.getUserId()); // 3. 将类型列表设置到request请求域中 request.setAttribute("typeList", typeList); // 4. 设置首页动态包含的页面值 request.setAttribute("changePage","note/view.jsp"); // 5. 请求转发跳转到index.jsp request.getRequestDispatcher("index.jsp").forward(request, response); }}
- NoteTypeServlet
package com.lezijie.note.web;import com.lezijie.note.po.NoteType;import com.lezijie.note.po.User;import com.lezijie.note.service.NoteTypeService;import com.lezijie.note.util.JsonUtil;import com.lezijie.note.vo.ResultInfo;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;@WebServlet("/type")public class NoteTypeServlet extends HttpServlet { private NoteTypeService typeService = new NoteTypeService(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置首页导航的高亮值 request.setAttribute("menu_page", "type"); // 得到用户行为 String actionName = request.getParameter("actionName"); // 判断用户行为 if ("list".equals(actionName)) { // 查询类型列表 typeList(request, response); } else if ("delete".equals(actionName)) { // 删除类型 deleteType(request, response); } else if ("addOrUpdate".equals(actionName)) { // 添加或修改类型 addOrUpdate(request, response); } } /** * 添加或修改类型 1. 接收参数 (类型名称、类型ID) 2. 获取Session作用域中的user对象,得到用户ID 3. 调用Service层的更新方法,返回ResultInfo对象 4. 将ResultInfo转换成JSON格式的字符串,响应给ajax的回调函数 * @param request * @param response */ private void addOrUpdate(HttpServletRequest request, HttpServletResponse response) { // 1. 接收参数 (类型名称、类型ID) String typeName = request.getParameter("typeName"); String typeId = request.getParameter("typeId"); // 2. 获取Session作用域中的user对象,得到用户ID User user = (User) request.getSession().getAttribute("user"); // 3. 调用Service层的更新方法,返回ResultInfo对象 ResultInfo resultInfo = typeService.addOrUpdate(typeName, user.getUserId(), typeId); // 4. 将ResultInfo转换成JSON格式的字符串,响应给ajax的回调函数 JsonUtil.toJson(response, resultInfo); } /** * 删除类型 1. 接收参数(类型ID) 2. 调用Service的更新操作,返回ResultInfo对象 3. 将ResultInfo对象转换成JSON格式的字符串,响应给ajax的回调函数 * @param request * @param response */ private void deleteType(HttpServletRequest request, HttpServletResponse response) { // 1. 接收参数(类型ID) String typeId = request.getParameter("typeId"); // 2. 调用Service的更新操作,返回ResultInfo对象 ResultInfo resultInfo = typeService.deleteType(typeId); // 3. 将ResultInfo对象转换成JSON格式的字符串,响应给ajax的回调函数 JsonUtil.toJson(response, resultInfo); } /** * 查询类型列表 1. 获取Session作用域设置的user对象 2. 调用Service层的查询方法,查询当前登录用户的类型集合,返回集合 3. 将类型列表设置到request请求域中 4. 设置首页动态包含的页面值 5. 请求转发跳转到index.jsp页面 * @param request * @param response */ private void typeList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取Session作用域设置的user对象 User user = (User) request.getSession().getAttribute("user"); // 2. 调用Service层的查询方法,查询当前登录用户的类型集合,返回集合 List typeList = typeService.findTypeList(user.getUserId()); // 3. 将类型列表设置到request请求域中 request.setAttribute("typeList", typeList); // 4. 设置首页动态包含的页面值 request.setAttribute("changePage","type/list.jsp"); // 5. 请求转发跳转到index.jsp页面 request.getRequestDispatcher("index.jsp").forward(request, response); }}
- ReportServlet
package com.lezijie.note.web;import com.lezijie.note.po.Note;import com.lezijie.note.po.User;import com.lezijie.note.service.NoteService;import com.lezijie.note.util.JsonUtil;import com.lezijie.note.vo.ResultInfo;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;import java.util.Map;@WebServlet("/report")public class ReportServlet extends HttpServlet { private NoteService noteService = new NoteService(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置首页导航栏的高亮值 request.setAttribute("menu_page", "report"); // 得到用户行为 String actionName = request.getParameter("actionName"); // 判断用户行为 if ("info".equals(actionName)) { // 进入报表页面 reportInfo(request, response); } else if ("month".equals(actionName)) { // 通过月份查询对应的云记数量 queryNoteCountByMonth(request, response); } else if ("location".equals(actionName)) { // 查询用户发布云记时的坐标 queryNoteLonAndLat(request, response); } } /** * 查询用户发布云记时的坐标 * @param request * @param response */ private void queryNoteLonAndLat(HttpServletRequest request, HttpServletResponse response) { // 从Session作用域中获取用户对象 User user = (User) request.getSession().getAttribute("user"); // 调用Service层的查询方法,返回ResultInfo对象 ResultInfo<List> resultInfo = noteService.queryNoteLonAndLat(user.getUserId()); // 将ResultInfo对象转换成JSON格式的字符串,响应给AJAX的回调函数 JsonUtil.toJson(response, resultInfo); } /** * 通过月份查询对应的云记数量 * @param request * @param response */ private void queryNoteCountByMonth(HttpServletRequest request, HttpServletResponse response) { // 从Session作用域中获取用户对象 User user = (User) request.getSession().getAttribute("user"); // 调用Service层的查询方法,返回ResultInfo对象 ResultInfo<Map> resultInfo = noteService.queryNoteCountByMonth(user.getUserId()); // 将ResultInfo对象转换成JSON格式的字符串,响应给ajax的回调函数 JsonUtil.toJson(response, resultInfo); } /** * 进入报表页面 * @param request * @param response */ private void reportInfo(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置首页动态包含的页面值 request.setAttribute("changePage","report/info.jsp"); // 请求转发跳转到index.jsp request.getRequestDispatcher("index.jsp").forward(request, response); }}
- UserServlet
package com.lezijie.note.web;import com.lezijie.note.po.User;import com.lezijie.note.service.UserService;import com.lezijie.note.vo.ResultInfo;import org.apache.commons.io.FileUtils;import javax.servlet.ServletException;import javax.servlet.annotation.MultipartConfig;import javax.servlet.annotation.WebServlet;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.IOException;@WebServlet("/user")@MultipartConfigpublic class UserServlet extends HttpServlet { private UserService userService = new UserService(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置首页导航高亮 request.setAttribute("menu_page", "user"); // 接收用户行为 String actionName = request.getParameter("actionName"); // 判断用户行为,调用对应的方法 if ("login".equals(actionName)) { // 用户登录 userLogin(request, response); } else if ("logout".equals(actionName)) { // 用户退出 userLogOut(request, response); } else if ("userCenter".equals(actionName)) { // 进入个人中心 userCenter(request, response); } else if ("userHead".equals(actionName)) { // 加载头像 userHead(request, response); } else if ("checkNick".equals(actionName)) { // 验证昵称的唯一性 checkNick(request, response); } else if ("updateUser".equals(actionName)) { // 修改用户信息 updateUser(request, response); } } /** * 修改用户信息 注:文件上传必须在Servlet类上提那家注解!!! @MultipartConfig 1. 调用Service层的方法,传递request对象作为参数,返回resultInfo对象 2. 将resultInfo对象存到request作用域中 3. 请求转发跳转到个人中心页面 (user?actionName=userCenter) * @param request * @param response */ private void updateUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 调用Service层的方法,传递request对象作为参数,返回resultInfo对象 ResultInfo resultInfo = userService.updateUser(request); // 2. 将resultInfo对象存到request作用域中 request.setAttribute("resultInfo", resultInfo); // 3. 请求转发跳转到个人中心页面 (user?actionName=userCenter) request.getRequestDispatcher("user?actionName=userCenter").forward(request, response); } /** * 验证昵称的唯一性 * 1. 获取参数(昵称) * 2. 从session作用域获取用户对象,得到用户ID * 3. 调用Service层的方法,得到返回的结果 * 4. 通过字符输出流将结果响应给前台的ajax的回调函数 * 5. 关闭资源 * @param request * @param response */ private void checkNick(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 获取参数(昵称) String nick = request.getParameter("nick"); // 2. 从session作用域获取用户对象,得到用户ID User user = (User) request.getSession().getAttribute("user"); // 3. 调用Service层的方法,得到返回的结果 Integer code = userService.checkNick(nick, user.getUserId()); // 4. 通过字符输出流将结果响应给前台的ajax的回调函数 response.getWriter().write(code + ""); // 5. 关闭资源 response.getWriter().close(); } /** * 加载头像 * 1. 获取参数 (图片名称) * 2. 得到图片的存放路径 (request.getServletContext().getealPathR("/")) * 3. 通过图片的完整路径,得到file对象 * 4. 通过截取,得到图片的后缀 * 5. 通过不同的图片后缀,设置不同的响应的类型 * 6. 利用FileUtils的copyFile()方法,将图片拷贝给浏览器 * @param request * @param response */ private void userHead(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 获取参数 (图片名称) String head = request.getParameter("imageName"); // 2. 得到图片的存放路径 (得到项目的真实路径:request.getServletContext().getealPathR("/")) String realPath = request.getServletContext().getRealPath("/WEB-INF/upload/"); // 3. 通过图片的完整路径,得到file对象 File file = new File(realPath + "/" + head); // 4. 通过截取,得到图片的后缀 String pic = head.substring(head.lastIndexOf(".")+1); // 5. 通过不同的图片后缀,设置不同的响应的类型 if ("PNG".equalsIgnoreCase(pic)) { response.setContentType("image/png"); } else if ("JPG".equalsIgnoreCase(pic) || "JPEG".equalsIgnoreCase(pic)) { response.setContentType("image/jpeg"); } else if ("GIF".equalsIgnoreCase(pic)) { response.setContentType("image/gif"); } // 6. 利用FileUtils的copyFile()方法,将图片拷贝给浏览器 FileUtils.copyFile(file, response.getOutputStream()); } /** * 进入个人中心 * 1. 设置首页动态包含的页面值 * 2. 请求转发跳转到index.jsp * @param request * @param response */ private void userCenter(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 设置首页动态包含的页面值 request.setAttribute("changePage", "user/info.jsp"); // 2. 请求转发跳转到index request.getRequestDispatcher("index.jsp").forward(request, response); } /** * 用户退出 * 1. 销毁Session对象 * 2. 删除Cookie对象 * 3. 重定向跳转到登录页面 * @param request * @param response */ private void userLogOut(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 销毁Session对象 request.getSession().invalidate(); // 2. 删除Cookie对象 Cookie cookie = new Cookie("user", null); cookie.setMaxAge(0); // 设置0,表示删除cookie response.addCookie(cookie); // 3. 重定向跳转到登录页面 response.sendRedirect("login.jsp"); } /** * 用户登录 1. 获取参数 (姓名、密码) 2. 调用Service层的方法,返回ResultInfo对象 3. 判断是否登录成功 如果失败 将resultInfo对象设置到request作用域中 请求转发跳转到登录页面 如果成功 将用户信息设置到session作用域中 判断用户是否选择记住密码(rem的值是1) 如果是,将用户姓名与密码存到cookie中,设置失效时间,并响应给客户端 如果否,清空原有的cookie对象 重定向跳转到index页面 * @param request * @param response */ private void userLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取参数 (姓名、密码) String userName = request.getParameter("userName"); String userPwd = request.getParameter("userPwd"); // 2. 调用Service层的方法,返回ResultInfo对象 ResultInfo resultInfo = userService.userLogin(userName, userPwd); // 3. 判断是否登录成功 if (resultInfo.getCode() == 1) { // 如果成功 // 将用户信息设置到session作用域中 request.getSession().setAttribute("user", resultInfo.getResult()); // 判断用户是否选择记住密码(rem的值是1) String rem = request.getParameter("rem"); // 如果是,将用户姓名与密码存到cookie中,设置失效时间,并响应给客户端 if ("1".equals(rem)) { // 得到Cookie对象 Cookie cookie = new Cookie("user",userName +"-"+userPwd); // 设置失效时间 cookie.setMaxAge(3*24*60*60); // 响应给客户端 response.addCookie(cookie); } else { // 如果否,清空原有的cookie对象 Cookie cookie = new Cookie("user", null); // 删除cookie,设置maxage为0 cookie.setMaxAge(0); // 响应给客户端 response.addCookie(cookie); } // 重定向跳转到index页面 response.sendRedirect("index"); } else { // 失败 // 将resultInfo对象设置到request作用域中 request.setAttribute("resultInfo", resultInfo); // 请求转发跳转到登录页面 request.getRequestDispatcher("login.jsp").forward(request, response); } }}
9.2 webapp目录
……
10、报错记录
10.1 问题描述:「 在代码不出错的情况下,(判断是否为空)点击“登录”按钮 并未出现提示信息 」
10.2 问题描述:「 tomcat端口冲突解决 Address already in use: JVM_Bind :8080 」
「 最可能的解决方案: 」
① cmd 命令输入 netstat –ano | findstr 8080
② 查看到 8080端口对应的进程号xxxx
③ 在任务管理器中寻找改PID
④ 右键结束该任务 或者 仍然在命令行下输入 taskkill –pid xxxx
如果上面方法没有解决 选择重启电脑
转到index
request.getRequestDispatcher(“index.jsp”).forward(request, response);
}/** * 用户退出 * 1. 销毁Session对象 * 2. 删除Cookie对象 * 3. 重定向跳转到登录页面 * @param request * @param response */private void userLogOut(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 销毁Session对象 request.getSession().invalidate(); // 2. 删除Cookie对象 Cookie cookie = new Cookie("user", null); cookie.setMaxAge(0); // 设置0,表示删除cookie response.addCookie(cookie); // 3. 重定向跳转到登录页面 response.sendRedirect("login.jsp");}/** * 用户登录 1. 获取参数 (姓名、密码) 2. 调用Service层的方法,返回ResultInfo对象 3. 判断是否登录成功 如果失败 将resultInfo对象设置到request作用域中 请求转发跳转到登录页面 如果成功 将用户信息设置到session作用域中 判断用户是否选择记住密码(rem的值是1) 如果是,将用户姓名与密码存到cookie中,设置失效时间,并响应给客户端 如果否,清空原有的cookie对象 重定向跳转到index页面 * @param request * @param response */private void userLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取参数 (姓名、密码) String userName = request.getParameter("userName"); String userPwd = request.getParameter("userPwd"); // 2. 调用Service层的方法,返回ResultInfo对象 ResultInfo resultInfo = userService.userLogin(userName, userPwd); // 3. 判断是否登录成功 if (resultInfo.getCode() == 1) { // 如果成功 // 将用户信息设置到session作用域中 request.getSession().setAttribute("user", resultInfo.getResult()); // 判断用户是否选择记住密码(rem的值是1) String rem = request.getParameter("rem"); // 如果是,将用户姓名与密码存到cookie中,设置失效时间,并响应给客户端 if ("1".equals(rem)) { // 得到Cookie对象 Cookie cookie = new Cookie("user",userName +"-"+userPwd); // 设置失效时间 cookie.setMaxAge(3*24*60*60); // 响应给客户端 response.addCookie(cookie); } else { // 如果否,清空原有的cookie对象 Cookie cookie = new Cookie("user", null); // 删除cookie,设置maxage为0 cookie.setMaxAge(0); // 响应给客户端 response.addCookie(cookie); } // 重定向跳转到index页面 response.sendRedirect("index"); } else { // 失败 // 将resultInfo对象设置到request作用域中 request.setAttribute("resultInfo", resultInfo); // 请求转发跳转到登录页面 request.getRequestDispatcher("login.jsp").forward(request, response); }}
}
### 9.2 webapp目录 > ……## 10、报错记录### 10.1 问题描述:「 在代码不出错的情况下,(判断是否为空)点击“登录”按钮 并未出现提示信息 」### 10.2 问题描述:「 tomcat端口冲突解决 Address already in use: JVM_Bind :8080 」「 **最可能的解决方案:** 」 ① cmd 命令输入 netstat –ano | findstr 8080 ② 查看到 8080端口对应的进程号xxxx③ 在任务管理器中寻找改PID④ 右键结束该任务 或者 仍然在命令行下输入 taskkill –pid xxxx> **如果上面方法没有解决 选择重启电脑**