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 配置文件中,修改配置、添加依赖与插件
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.lezijie</groupId><artifactId>lezijie-note</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>lezijie-note Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><!-- junit 测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- web servlet --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><!-- 日志打印相关的jar --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.2</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.2</version></dependency><!-- mysql 驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.19</version></dependency><!-- json 依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency><!-- hutool工具集 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.4.7</version></dependency><!-- commons-io 依赖 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency><!-- 添加百度编辑器ueditor支持 --><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency><!-- jstl依赖 --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- lombok插件 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency></dependencies><build><finalName>lezijie-note</finalName><plugins><!-- 编译环境插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><!-- Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><port>8080</port> <!-- 启动端口 默认:8080 --><path>/note</path> <!-- 项目的站点名,即对外访问路径 --><server>tomcat7</server> <!-- 服务器名称 --></configuration></plugin></plugins></build></project>

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 {
@Test
public 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.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.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.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.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.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.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-dd
HH: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<Object> 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) {// 循环设置参数,设置参数类型为Objectfor (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<Object> 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) {// 循环设置参数,设置参数类型为Objectfor (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<Object> 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) {// 循环设置参数,设置参数类型为Objectfor (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<Object> 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<Object> 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<Object> 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<Note> 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<Object> 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<Note> noteList = BaseDao.queryRows(sql, params, Note.class);return noteList;}/*** 通过日期分组查询当前登录用户下的云记数量* @param userId* @return*/public List<NoteVo> 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<Object> params = new ArrayList<>();params.add(userId);// 调用BaseDao的查询方法List<NoteVo> list = BaseDao.queryRows(sql, params, NoteVo.class);return list;}/*** 通过类型分组查询当前登录用户下的云记数量* @param userId* @return*/public List<NoteVo> 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<Object> params = new ArrayList<>();params.add(userId);// 调用BaseDao的查询方法List<NoteVo> list = BaseDao.queryRows(sql, params, NoteVo.class);return list;}/*** 通过id查询云记对象* @param noteId* @return*/public Note findNoteById(String noteId) {// 定义SQLString 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<Object> 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<Object> params = new ArrayList<>();params.add(noteId);// 调用BaseDaoint row = BaseDao.executeUpdate(sql, params);return row;}/*** 通过用户ID查询云记列表* @param userId* @return*/public List<Note> 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<Object> params = new ArrayList<>();params.add(userId);// 调用BaseDaoList<Note> 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<NoteType> findTypeListByUserId(Integer userId) {// 1. 定义SQL语句String sql = "select typeId,typeName,userId from tb_note_type where userId = ? ";// 2. 设置参数列表List<Object> params = new ArrayList<>();params.add(userId);// 3. 调用BaseDao的查询方法,返回集合List<NoteType> 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<Object> params = new ArrayList<>();params.add(typeId);// 调用BaseDaolong 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<Object> params = new ArrayList<>();params.add(typeId);// 调用BaseDaoint 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<Object> 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<Object> 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<Object> 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<Object> 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<Object> 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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 基于HTTPHttpServletRequest 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*/@Overridepublic 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;/*** 非法访问拦截* 拦截的资源:* 所有的资源   /** <p>* 需要被放行的资源* 1. 指定页面,放行 (用户无需登录的即可访问的页面;例如:登录页面login.jsp、注册页面register.jsp等)* 2. 静态资源,放行 (存放在statics目录下的资源;例如:js、css、images等)* 3. 指定行为,放行 (用户无需登录即可执行的操作;例如:登录操作actionName=login等)* 4. 登录状态,放行 (判断session作用域中是否存在user对象;存在则放行,不存在,则拦截跳转到登录页面)* <p>* 免登录(自动登录)* 通过Cookie和Session对象实现* <p>* 什么时候使用免登录:* 当用户处于未登录状态,且去请求需要登录才能访问的资源时,调用自动登录功能* <p>* 目的:* 让用户处于登录状态(自动调用登录方法)* <p>* 实现:* 从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* <p>* 如果以上判断都不满足,则拦截跳转到登录页面*/
@WebFilter("/*")
public class LoginAccessFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {// 基于HTTPHttpServletRequest 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. returnreturn;}}}// 拦截请求,重定向跳转到登录页面response.sendRedirect("login.jsp");}@Overridepublic void destroy() {}
}

9.1.3 po层

  • Note
package com.lezijie.note.po;import lombok.Getter;
import lombok.Setter;import java.util.Date;@Getter
@Setter
public class Note {private Integer noteId; // 云记IDprivate String title; // 云记标题private String content; // 云记内容private Integer typeId; // 云记类型IDprivate Date pubTime; // 发布时间private Float lon; // 经度private Float lat; // 纬度private String typeName;
}
  • NoteType
package com.lezijie.note.po;import lombok.Getter;
import lombok.Setter;@Getter
@Setter
public class NoteType {private Integer typeId; // 类型IDprivate String typeName; // 类型名称private Integer userId; // 用户ID
}
  • User
package com.lezijie.note.po;import lombok.Getter;
import lombok.Setter;@Getter
@Setter
public class User {private Integer userId; // 用户IDprivate 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<Note> addOrUpdate(String typeId, String title,String content, String noteId, String lon, String lat) {ResultInfo<Note> 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.915if (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. 判断总记录数是否大于04. 如果总记录数大于0,调用Page类的带参构造,得到其他分页参数的值,返回Page对象5. 查询当前登录用户下当前页的数据列表,返回note集合6. 将note集合设置到page对象中7. 返回Page对象* @param pageNumStr* @param pageSizeStr* @param userId* @param title  条件查询的参数:标题* @return*/public Page<Note> 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. 判断总记录数是否大于0if (count < 1) {return null;}// 4. 如果总记录数大于0,调用Page类的带参构造,得到其他分页参数的值,返回Page对象Page<Note> page = new Page<>(pageNum, pageSize, count);// 得到数据库中分页查询的开始下标Integer index = (pageNum -1) * pageSize;// 5. 查询当前登录用户下当前页的数据列表,返回note集合List<Note> noteList = noteDao.findNoteListByPage(userId, index, pageSize, title, date, typeId);// 6. 将note集合设置到page对象中page.setDataList(noteList);// 7. 返回Page对象return page;}/*** 通过日期分组查询当前登录用户下的云记数量* @param userId* @return*/public List<NoteVo> findNoteCountByDate(Integer userId) {return noteDao.findNoteCountByDate(userId);}/*** 通过类型分组查询当前登录用户下的云记数量* @param userId* @return*/public List<NoteVo> 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. 判断受影响的行数是否大于0if (row > 0) {return 1;}return 0;}/*** 通过月份查询对应的云记数量* @param userId* @return*/public ResultInfo<Map<String, Object>> queryNoteCountByMonth(Integer userId) {ResultInfo<Map<String, Object>> resultInfo = new ResultInfo<>();// 通过月份分类查询云记数量List<NoteVo> noteVos = noteDao.findNoteCountByDate(userId);// 判断集合是否存在if (noteVos != null && noteVos.size() > 0) {// 得到月份List<String> monthList = new ArrayList<>();// 得到云记集合List<Integer> noteCountList = new ArrayList<>();// 遍历月份分组集合for (NoteVo noteVo: noteVos) {monthList.add(noteVo.getGroupName());noteCountList.add((int)noteVo.getNoteCount());}// 准备Map对象,封装对应的月份与云记数量Map<String, Object> 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<Note>> queryNoteLonAndLat(Integer userId) {ResultInfo<List<Note>> resultInfo = new ResultInfo<>();// 通过用户ID查询云记列表List<Note> 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<NoteType> findTypeList(Integer userId) {List<NoteType> 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<NoteType> deleteType(String typeId) {ResultInfo<NoteType> 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. 判断受影响的行数是否大于0if (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<Integer> addOrUpdate(String typeName, Integer userId, String typeId) {ResultInfo<Integer> 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. 判断 主键/受影响的行数 是否大于0if (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<User> userLogin(String userName, String userPwd) {ResultInfo<User> 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<User> updateUser(HttpServletRequest request) {ResultInfo<User> 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
@Setter
public class Page<T> {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<T> 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 < 1 ? 1 : pageNum - 1;// 下一页  (当前页+1;如果当前页+1大于总页数,则下一页为总页数的值)this.nextPage = 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 < 1) {// 如果当前页-5小于1,则导航开始页为1this.startNavPage = 1;// 此时导航结束页为导航开始数+9;如果导航开始数+9大于总页数,则导航结束页为总页数this.endNavPage = this.startNavPage + 9 > totalPages ? totalPages : this.startNavPage + 9;}// 导航结束页 (当前页+4;如果当前页+4大于总页数,则导航结束页为总页数,此时导航开始页为导航结束页-9;如果导航结束页-9小于1,则导航开始页为1)if (this.endNavPage > totalPages) {// 如果当前页+4大于总页数,则导航结束页为总页数this.endNavPage = totalPages;// 此时导航开始页为导航结束页-9;如果导航结束页-9小于1,则导航开始页为1this.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
@Setter
public 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
@Setter
public class ResultInfo<T> {private Integer code; // 状态码 成功=1,失败=0private 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 {@Overrideprotected 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)) { // 类型查询// 得到查询条件:类型IDString 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.jsprequest.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<Note> page = new NoteService().findNoteListByPage(pageNum, pageSize, user.getUserId(), title, date, typeId);// 4. 将page对象设置到request作用域中request.setAttribute("page", page);// 通过日期分组查询当前登录用户下的云记数量List<NoteVo> dateInfo = new NoteService().findNoteCountByDate(user.getUserId());// 设置集合存放在request作用域中request.getSession().setAttribute("dateInfo", dateInfo);// 通过类型分组查询当前登录用户下的云记数量List<NoteVo> 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();@Overrideprotected 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.jsprequest.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");// 如果是修改操作,需要接收noteIdString noteId = request.getParameter("noteId");// 2. 调用Service层方法,返回resultInfo对ResultInfo<Note> resultInfo = noteService.addOrUpdate(typeId, title, content, noteId, lon, lat);// 3. 判断resultInfo的code值if (resultInfo.getCode() == 1) {// 重定向跳转到首页 indexresponse.sendRedirect("index");} else {// 将resultInfo对象设置到request作用域request.setAttribute("resultInfo", resultInfo);// 请求转发跳转到note?actionName=viewString url = "note?actionName=view";// 如果是修改操作,需要传递noteIdif (!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 {/* 修改操作 */// 得到要修改的云记IDString 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<NoteType> typeList = new NoteTypeService().findTypeList(user.getUserId());// 3. 将类型列表设置到request请求域中request.setAttribute("typeList", typeList);// 4. 设置首页动态包含的页面值request.setAttribute("changePage","note/view.jsp");// 5. 请求转发跳转到index.jsprequest.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();@Overrideprotected 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对象,得到用户ID3. 调用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对象,得到用户IDUser user = (User) request.getSession().getAttribute("user");// 3. 调用Service层的更新方法,返回ResultInfo对象ResultInfo<Integer> 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<NoteType> 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<NoteType> 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();@Overrideprotected 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<Note>> 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<String, Object>> 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.jsprequest.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")
@MultipartConfig
public class UserServlet extends HttpServlet {private UserService userService = new UserService();@Overrideprotected 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类上提那家注解!!! @MultipartConfig1. 调用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<User> 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作用域获取用户对象,得到用户IDUser 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. 请求转发跳转到indexrequest.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,表示删除cookieresponse.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<User> 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为0cookie.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,表示删除cookieresponse.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<User> 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为0cookie.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 <null>:8080 」「 **最可能的解决方案:** 」① cmd 命令输入 netstat –ano | findstr 8080② 查看到 8080端口对应的进程号xxxx③ 在任务管理器中寻找改PID
④ 右键结束该任务 或者 仍然在命令行下输入 taskkill –pid xxxx> **如果上面方法没有解决 选择重启电脑**

Java项目——云R记相关推荐

  1. 云效(原RDC)如何构建一个基于Maven的Java项目

    最近在将公司的持续集成架构做一个系统的调整,调整过程中受到了RDC团队大量的帮助,所以利用国庆时间写了几篇RDC的分享,希望能让更多的人了解和用好RDC这个产品. 我会把我最近3个月的使用体会分成5个 ...

  2. 云服务器开启ftp_阿里云搭建wordpress 及部署java项目

    很久之前,小编就买了一年的阿里云服务器,也购买了域名,一直都没有时间,加上自己对linux的知识不足,最后小编终于把wordpress和tomcat同时部署在一个服务器上, 先简单说说阿里云的购买流程 ...

  3. 【CSDN】-京东云部署java项目及性能测试

    前言: 最近因为华为云服务器购买过期了,其实本来自己的个人项目部署或不部署到服务器都是可以的.但最近刚好看见京东云服务器在做活动.就想着搞一搞.刚好官方送了我一张代金券.那我就直接用起来吧. 个人需求 ...

  4. Myeclipse10.7安装git插件并将Java项目上传到码云(github)

    注:本文来源:外匹夫的<Myeclipse10.7安装git插件并将Java项目上传到码云(github)> 一.先说说安装egit插件的步骤(安装egit不成功的原因主要是下载的egit ...

  5. 【华为云实战开发】1.传统Java项目怎么能变得高大上?

    1 概述 1.1 文章目的 本文主要想为研发Java项目的企业或个人提供上云指导,通过本文中的示例项目 "小幺鸡",为开发者提供包括项目管理,代码托管,代码检查,编译构建,测试管理 ...

  6. 阿里云轻量云服务器部署java项目

    阿里云轻量云服务器部署java项目 前言:阿里云最新推出了轻量云服务器,说是可以简化配置.看重他是因为带宽明显提升.就继续照着ecs服务器的方式安装了一系列环境.系统是阿里云的Centos7.3.JD ...

  7. 阿里云轻量级云服务器部署Java项目

    一.MySQL安装与配置 1.MySQL安装 配置yum源,mkdir在/usr/local目录下新建mysql目录 进入mysql目录 cd /usr/local/mysql 执行下面命令 wget ...

  8. 码云上面优秀的java项目_秒建一个后台管理系统?用这5个开源免费的Java项目就够了...

    以下推荐项目都是码云上的优质项目,并且都是项目快速开发脚手架,代码质量什么的无法保证能有多好,毕竟很多也是个人开发,或多或少也有个人色彩影响. 不过既然开源出来,这么多人参与,一般情况下项目整体质量可 ...

  9. Java项目部署到云服务器的思路

    Java项目部署到云服务器的思路 1 部署项目的前提条件 1.1 购买云服务器 我购买的是腾讯云的服务器,第一年享优惠88一年 cpu好像两核的,作为入门级的也算够用了 如果第二年该续费的时候,我记得 ...

最新文章

  1. 如何正确选择聚类算法? | CSDN博文精选
  2. lnmp架构——nginx的负载均衡
  3. kafaka使用 消息队列_Java使用消息队列还是直接使用线程池ExecutorService异步处理?...
  4. nginx: [emerg] socket() [::]:80 failed (97: Address family not supported by protocol)
  5. DbLookUpCombobox的使用方法
  6. [Amaze UI] 如何推进 mobile first 的前端 Web 方案
  7. XCTF_Web_新手练习区:webshell
  8. mathematica练习程序(图像取反)
  9. mysql查询男生基本情况_MySQL数据库技术与应用:数据查询
  10. Android进程间通信之socket通信
  11. Android 爆高危漏洞,华为小米皆中招;第三代苹果 AirPods 来了;SQLite 3.30.0 发布 | 极客头条...
  12. aes 结尾 特殊字符_乔迁庆典主持词开头及结尾
  13. 基于Docker布署伪分布式hadoop环境(一)
  14. 拓端tecdat|Python多项式Logistic逻辑回归进行多类别分类和交叉验证准确度箱线图可视化
  15. 既有禀赋上的自然延展:中国移动咪咕进军元宇宙的底层逻辑
  16. iOS端抓包工具-stream
  17. win8计算机无法安装打印机驱动程序,win8系统安装打印机驱动失败怎么办|win8系统安装打印机驱动失败的解决方法...
  18. 面试题之10亿正整数问题
  19. 【原创】RPA在BPO领域的场景分享-中科云创CEO每日分享
  20. 我觉得,我认为。。。

热门文章

  1. Python3.8 新特性:f-strings调试
  2. 【Blender批量合并fbx动画到单个gltf】
  3. 优化-处理大量定时任务的思路
  4. 原生JS实现弹幕的简单操作速成
  5. 百家号同步公众号的自媒体工具有吗?
  6. SWUST OJ954: 单链表的链接
  7. 解决 WKWebView goback执行无效的bug
  8. 古剑奇谭2打砺罂10分钟过的方法!
  9. USB专用充电端口(DCP) MST2515
  10. 牛逼的Python库MoviePy!利用Python自动剪辑tiktok视频!