> 文档中心 > Java项目——云R记

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 += "&noteId="+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> **如果上面方法没有解决 选择重启电脑**