很抱歉,同时写几个系列并且本人在考试月,真的有点忙不过来,也要复习一些考试知识,所以更新得有点慢,但我会坚持更新这些系列的。请大家放心。今天要更的是Maven+SpringMVC+Hibernate的项目并附带分页功能以及一对多查询功能。
文章结构:1.项目介绍(功能业务逻辑,运用的知识,项目数据库等);2.项目架构介绍以及部分关键逻辑代码说明(分页以及一对多查询功能的实现(通过PagingAndSortingRepository实现))。3.源码分享。
本系列:J2EE项目系列
一、项目介绍(功能业务逻辑,运用的知识,项目数据库等)
(1)功能介绍:
1.添加管理账号,包括账号、密码,你的名字(新旧名字)。还有一系列的增删改查。
2.添加博客文章,文章的日期、内容、标题、id。还有一系列的增删改查。
3.实现外键级联属性
4.实现分页查询统计
5.实现一对多查询
6.部分前端代码,基于bootstrap的样式和js.min
(2)运用的知识:
使用Intellij进行开发的,spring,hibernate,mysql,maven
1.基本数据库知识MySQL
2.SpringMVC+hibernate
3.(重点)框架的MVC设计模式的应用
4.(重点)分页查询
5.(重点)一对多查询
6.部分前端代码,基于bootstrap的样式和js.min以及一些jstl
7.JpaRepository的使用
(3)项目构建:使用Maven快速构建项目
给出maven代码并讲解
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fuzhu</groupId>
<artifactId>springmvcdemo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>springmvcdemo Maven Webapp</name>
<url>http://maven.apache.org</url>
<!--springcore的。虽然我们只写了一个依赖,但是它导入了两个jar包,也就是说,导入某个jar包时,与它密切相关的jar包也会同时被导入进来。-->
<properties>
<spring.version>4.2.6.RELEASE</spring.version>
<hibernate.version>5.1.0.Final</hibernate.version>
</properties>
<dependencies>
<!--servlet的-->
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>tjws</artifactId>
<version>3.0.10.Final</version>
<scope>test</scope>
</dependency>
<!--junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring基本包-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.10.1.RELEASE</version>
</dependency>
<!--hibernate基本包-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
</dependency>
</dependencies>
<build>
<finalName>springmvcdemo</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
(4)项目分包:MVC架构。对比我的上一篇项目,使用框架的优势就完美体现出来了。极度精简的代码,项目代码设计。

这里写图片描述
(5)数据库:
//user表
CREATE TABLE user(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nickname VARCHAR(45) NOT NULL,
password VARCHAR(45) NOT NULL,
first_name VARCHAR(45),
last_name VARCHAR(45)
);
//blog表
CREATE TABLE blog(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100),
content VARCHAR(100),
user_id INT(11) UNSIGNED,
pub_date DATE
);
大家需要使用工具去添加外键,我就这样偷懒了。哈哈
添加外键 user_id--id
测试数据:
INSERT INTO `t2`.`blog` (`title`, `content`, `user_id`, `pub_date`) VALUES ('发发发方法付', '发发发方法付付付', '1', '2016-12-29');
INSERT INTO `t2`.`user` (`nickname`, `password`, `first_name`, `last_name`) VALUES ('fuzhu', '75111', 'fuzh', 'fuzhu');
(6)项目功能截图:
下面是用户表的增删改查

这里写图片描述
下面是实现一对多的查询

这里写图片描述
下面是博客文章的总表,并实现分页查询

这里写图片描述
二、项目架构介绍以及部分关键逻辑代码说明
基本的MVC架构了,model-view-controller
大家学习持久层开发的时候可以使用JpaRepository。本博客也是使用这个。这个是详细文档Spring Data
此分层的结构:(注意篇)项目一些坑以及配置过程(1)user业务逻辑的的接口;(2)blog业务的逻辑接口;(3)分页功能的接口;(4)细讲分页功能(含JpaRepository使用);(5)细讲一对多查询功能(含JpaRepository使用)
(注意篇)项目一些坑以及配置过程
(注意篇)1.项目配置系列,大家可根据这篇去配置我们的项目,暂不吐槽他的命名以及一些做法,但还是很详细and很多可取之处的。项目配置。在此感谢那位博主的付出。
(注意篇)2.即使按照他配置,还是有一些坑的。
<%@ page isELIgnored="false" %>
<!--这句代码非常重要!!!必须在jsp中添加,至于加在哪里,大家下载我的项目时候看jsp文件吧-->
<!--JSTL表达式语言可以使用标记格式方便地访问JSP的隐含对象和JavaBeans组件,JSTL的核心标记提供了流程和循环控制功能。自制标记也有自定义函数的功能-->
(注意篇)3.使用JpaRepository开发是有比较多坑的,大家需要先仔细阅读文档Spring Data。我的分页功能和一对多查询功能都是在这里学习的。不过我的是整合成项目,文档的是零散的。
比如jstl的使用,以及注意点,他的那个项目是有些小bug的。
(注意篇)4.注意下面的那个jsp文件里面,在<c:choose>这个标签里面是不支持注释的,用的时候注意把他们删了喔!!
(注意篇)5.大家可能注意到我用到了bootstrep以及js,也许不是单纯后端开发。大家看清楚,这里只是用到他的样式,我们把他删了也是可以的,只不过好看很多而已嘛。
(1)user业务逻辑的的接口
//像我给出的文档中一样,使用JpaRepository接口进行开发持久层
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Integer> {
@Modifying // 说明该方法是修改操作
@Transactional // 说明该方法是事务性操作
// 定义查询
// @Param注解用于提取参数
@Query("update UserEntity us set us.nickname=:qNickname, us.firstName=:qFirstName, us.lastName=:qLastName, us.password=:qPassword where us.id=:qId")
public void updateUser(@Param("qNickname") String nickname, @Param("qFirstName") String firstName,
@Param("qLastName") String qLastName, @Param("qPassword") String password, @Param("qId") Integer id);
}
(2)blog业务的逻辑接口
public interface BlogRepository extends JpaRepository<BlogEntity,Integer> {
// 修改博文操作
@Modifying
@Transactional
@Query("update BlogEntity blog set blog.title=:qTitle, blog.userByUserId.id=:qUserId," +
" blog.content=:qContent, blog.pubDate=:qPubDate where blog.id=:qId")
void updateBlog(@Param("qTitle") String title, @Param("qUserId") int userId, @Param("qContent") String content,
@Param("qPubDate") Date pubDate, @Param("qId") int id);
//一对多查询方法
@Query("select blog from BlogEntity blog where blog.userByUserId.id = ?1")
List<BlogEntity> findByUserByUserId(int userId);
}
(3)分页功能的接口
//可直接装配使用的。
@Repository
public interface BlogPageDao extends PagingAndSortingRepository<BlogEntity, Long> {
}
(4)细讲分页功能(含JpaRepository使用)
//需要自动装配那几个接口咯
@Autowired
BlogRepository blogRepository;
@Autowired
UserRepository userRepository;
@Autowired
private BlogPageDao districtRepository;
// 查看所有博文,实现分页查询!!!注意是一个get请求,并且携带参数。
@RequestMapping(value = "/admin/blogs", method = RequestMethod.GET)
public String showBlogs(ModelMap modelMap,@RequestParam(value = "pageNonumber", required = false, defaultValue = "0") Integer pageNonumber) {
//如果pageNonumber,也就是当前页,要有特殊处理,奇葩的都弄到第一页
if (pageNonumber== null || pageNonumber==-1) {
pageNonumber= 0;
}
// pageNonumber是从0开始的,所以我们显示的时候要有特殊处理,这个是从数据库读取出来,不用特别处理
int pageSize = 5; //页面包含条数的多少
// PageRequest接口通常使用的起PageRequest实现类,其中封装了需要分页的信息。
PageRequest pageRequest = new PageRequest(pageNonumber, pageSize);
Page<BlogEntity> page = districtRepository.findAll(pageRequest);
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("当前第几页:" + page.getNumber());
System.out.println("总页数" + page.getTotalPages());
System.out.println("当前页面的list:" + page.getContent());
System.out.println("当前页面记录数:" + page.getNumberOfElements());
modelMap.addAttribute("sourceCodeList",page.getContent()); //当前页面的list
modelMap.addAttribute("totalPageNumber",page.getTotalElements());//总记录数
modelMap.addAttribute("numberPage",page.getNumber());//当前第几页
modelMap.addAttribute("totalPages",page.getTotalPages());//总页数
return "pages/testPage";
}
下面重点关注分页的几个点:1.传过来要按照map的key对应取值;2.注意sourceCodeList,totalPageNumber,numberPage,totalPages的处理。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<!-- 这个是重点!!!jstl使用获取数据的前提-->
<%@ page isELIgnored="false" %>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>SpringMVC 博客管理</title>
<title>分页page</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div layout:fragment="content">
<a href="/admin/blogs" class="list-group-item active">
你的博客文章
</a>
<table class="table table-bordered table-striped">
<tr>
<th>ID</th>
<th>标题</th>
<th>作者</th>
<th>发布日期</th>
<th>操作</th>
</tr>
<!--根据key得到的那个sourceCodeList就需要遍历出来,按照他包含的BlogEntitiy去读出来-->
<c:forEach items="${sourceCodeList}" var="blog">
<tr>
<td>${blog.id}</td>
<td>${blog.title}</td>
<td>${blog.userByUserId.nickname}, ${blog.userByUserId.firstName} ${blog.userByUserId.lastName}</td>
<td><fmt:formatDate value="${blog.pubDate }" pattern="yyyy-MM-dd"/></td>
<td>
<a href="/admin/blogs/show/${blog.id}" type="button" class="btn btn-sm btn-success">详情</a>
<a href="/admin/blogs/update/${blog.id}" type="button" class="btn btn-sm btn-warning">修改</a>
<a href="/admin/blogs/delete/${blog.id}" type="button" class="btn btn-sm btn-danger">删除</a>
</td>
</tr>
</c:forEach>
<tr>
<!--这里就是处理那几个传过来的page数据的啦,从而实现分页嘛-->
<td colspan="6" align="center" bgcolor="#5BA8DE">共${totalPageNumber}条记录 共${totalPages}页
当前第${numberPage+1}页<br>
<c:choose>
<!--这里处理是,numberPage 当前页不等于0的时候可以点击,也就是等于就点击不了咯-->
<c:when test="${numberPage!=0}">
<!--用了链接使用get请求,传想要去的那个页过去,其实就是在当前页上面做文章-->
<a href="${path}/admin/blogs?pageNonumber=${numberPage-1}"><input type="button"
name="previousPage"
value="上一页"/></a>
</c:when>
<c:otherwise>
<input type="button" disabled="disabled" name="previousPage" value="上一页"/>
</c:otherwise>
</c:choose>
<c:choose>
<!--这里处理是,numberPage 当前页不等于总页数减一的时候可以点击,也就是等于就点击不了咯-->
<c:when test="${numberPage != totalPages-1}">
<!--用了链接使用get请求,传想要去的那个页过去,其实就是在当前页上面做文章-->
<a href="${path}/admin/blogs?pageNonumber=${numberPage+1}"><input type="button" name="nextPage"
value="下一页"/></a>
</c:when>
<c:otherwise>
<input type="button" disabled="disabled" name="nextPage" value="下一页"/>
</c:otherwise>
</c:choose>
</td>
</tr>
</table>
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>
这样就实现一个分页功能啦!!!
(5)细讲一对多查询功能(含JpaRepository使用):
//使用这个接口实现分页查询开发
public interface BlogRepository extends JpaRepository<BlogEntity,Integer> {
// 修改博文操作
@Modifying
@Transactional
@Query("update BlogEntity blog set blog.title=:qTitle, blog.userByUserId.id=:qUserId," +
" blog.content=:qContent, blog.pubDate=:qPubDate where blog.id=:qId")
void updateBlog(@Param("qTitle") String title, @Param("qUserId") int userId, @Param("qContent") String content,
@Param("qPubDate") Date pubDate, @Param("qId") int id);
//一对多查询方法。我们要注意这个接口方法语句的拼接,很重要。
//blog.userByUserId.id 特别是这里,指的是user的id不是别的id
@Query("select blog from BlogEntity blog where blog.userByUserId.id = ?1")
List<BlogEntity> findByUserByUserId(int userId);
}
//功能:一对多的查询,查询自己的博客文章
@RequestMapping(value = "/admin/users/blogsDetails/{id}",method = RequestMethod.GET)
public String lookBlogs(ModelMap modelMap,@PathVariable("id") Integer userId){
//注意那个传过来的id
List<BlogEntity>blogEntityList = blogRepository.findByUserByUserId(userId);
for (BlogEntity blog :blogEntityList){
System.out.println("博客的啊啊啊啊啊啊"+blog.getId());
System.out.println(blog.getContent());
System.out.println(blog.getPubDate());
}
modelMap.addAttribute("blogList", blogEntityList);
return "admin/blogs";
}
下面是显示查询到的博客文章嘛,没啥特别的
<%--
Created by IntelliJ IDEA.
User: 符柱成
Date: 2016/12/29
Time: 21:26
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- 这个是重点!!!jstl使用获取数据的前提-->
<%@ page isELIgnored="false" %>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>SpringMVC 博客管理</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<![endif]-->
</head>
<body>
<div class="container">
<h1>SpringMVC 博客系统-博客管理</h1>
<hr/>
<h3>所有博客 <a href="/admin/blogs/add" type="button" class="btn btn-primary btn-sm">添加</a></h3>
<!-- 如果用户列表为空 -->
<c:if test="${empty blogList}">
<div class="alert alert-warning" role="alert">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>Blog表为空,请<a href="/admin/blogs/add"
type="button"
class="btn btn-primary btn-sm">添加</a>
</div>
</c:if>
<!-- 如果用户列表非空 -->
<c:if test="${!empty blogList}">
<table class="table table-bordered table-striped">
<tr>
<th>ID</th>
<th>标题</th>
<th>作者</th>
<th>发布日期</th>
<th>操作</th>
</tr>
<c:forEach items="${blogList}" var="blog">
<tr>
<td>${blog.id}</td>
<td>${blog.title}</td>
<td>${blog.userByUserId.nickname}, ${blog.userByUserId.firstName} ${blog.userByUserId.lastName}</td>
<td><fmt:formatDate value="${blog.pubDate }" pattern="yyyy-MM-dd"/></td>
<td>
<a href="/admin/blogs/show/${blog.id}" type="button" class="btn btn-sm btn-success">详情</a>
<a href="/admin/blogs/update/${blog.id}" type="button" class="btn btn-sm btn-warning">修改</a>
<a href="/admin/blogs/delete/${blog.id}" type="button" class="btn btn-sm btn-danger">删除</a>
</td>
</tr>
</c:forEach>
</table>
</c:if>
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>
三、对了,我会给我的源码给大家,大家想用就用吧。哈哈。喜欢就给个star咯,谢谢大家。
好了,J2EE项目系列(二)--博客管理系统(Maven+SpringMVC+Hibernate以及附加分页和一对多查询功能)讲完了,这是J2EE项目系列(二),这个系列我会继续写的,分享经验给大家。欢迎在下面指出错误,共同学习!!你的star是对我最好的支持!!
转载请注明:【JackFrost的博客】
网友评论