企业级博客项目笔记(二)
程序员文章站
2022-04-15 13:30:40
...
企业级博客项目笔记(二)
一、数据持久化
1.JPA简介
- JPA(Java Persistence API)是用于管理Java EE 和Java SE 环境中的持久化,以及对象/关系映射的Java API
- 封装JPA的框架有:EclipseLink、Hibernate、Apache OpenJPA
- 注意:实体实例被当做值以分离对象的方式进行传递(例如通过会话bean的远程业务接口),则该类必须实现Serializable接口---序列化接口
- 关系:
- 一对一:@OneToOne
- 一对多:@OneToMany
- 多对一:@ManyToOne
- 多对多:@ManyToMany
2.EntityManager
- EntityManager接口
- 定义用于与持久性上下文进行交互的方法
- 创建和删除持久实体实例,通过实体的主键查找实体
- 允许在实体上运行查询
- 获取EntityManager实例:
@PersistenceUnit
EntityManagerFactory emf;
EntityManager em;
@Resource
UserTransaction utx;
...
em=emf.createEntityManager();
try{
utx.begin();
em.persist(SomeEntity);
em.merge(AnotherEntity);
em.remove(ThirdEntity);
utx.commit();
}catch(Exception e){
utx.rollback();
}
- 查找实体
@PersistenceContext
EntityManager em;
public void enterOrder(int custID,CustomerOrder newOrder){
Customer cust=em.find(Customer.class,custID);
cust.getOrders().add(newOrder);
newOrder.setCustomer(cust);
}
3.Spring Data JPA
- Spring Data JPA简介
- 是更大的Spring Data家族的一部分
- 对基于JPA的数据访问层的增强支持
- 更容易构建基于使用Spring数据访问技术栈的应用程序
- CrudRepository接口:声明增删改查的方法
- PagingAndSortingRepository接口:声明分页和排序的方法
- Spring Data JPA 自定义接口(继承Repository接口)
- 根据方法名创建查询
public interface PersonRepository extends Repository<User,Long>{
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress,String lastname);
...
}
二、Spring Data JPA、Hibernate与Spring Boot集成
1.配置环境
- MySQL Community Server 5.7.17
- Spring Data JPA 1.11.1.RELEASE
- Hibernate 5.2.8.Final
- MySQL Connector/J 6.0.5
2.修改build.gradle
//依赖关系
dependencies{
...
//添加Spring Data JPA 的依赖
compile('org.springframework.boot:spring-boot-starter-data-jpa')
//添加MySQL连接驱动的依赖
compile('mysql:mysql-connector-java:6.0.5')
//添加H2数据库依赖
runtime('com.h2database:h2:1.4.193')
...
}
buildscript{
...
//自定义Hibernate的版本
ext['hibernate.version'] = '5.2.8.Final'
...
}
3.验证集成是否成功
- 打开cmd,运行
gradlew bootRun
- 打开浏览器访问项目,创建用户成功,说明集成成功
三、数据持久化实战
1.后台编码
- User.java
@Entity //实体
public class User {
@Id //主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //主键生成策略:自增
private Long id; //实体的唯一标识
private String name; //用户名称
private String email; //用户邮箱
protected User(){} //无参构造函数,设为protected防止直接使用
public User(Long id,String name,String email){
this.id=id;
this.name=name;
this.email=email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override //重写toString方法
public String toString(){
return String.format("User[id=%d,name='%s',email='%s']",id,name,email);
}
}
- UserRepository.java
public interface UserRepository extends CrudRepository<User,Long> {
}
- UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
/**
* 获取用户列表
* @param model
* @return
*/
@GetMapping
public ModelAndView list(Model model){
model.addAttribute("userList",userRepository.findAll());
model.addAttribute("title","用户管理");
return new ModelAndView("users/list","userModel",model);
}
/**
* 根据id查询用户
* @param id
* @param model
* @return
*/
@GetMapping("{id}")
public ModelAndView view(@PathVariable("id")Long id, Model model){
User user=userRepository.findOne(id);
model.addAttribute("user",user);
model.addAttribute("title","查看用户");
return new ModelAndView("users/view","userModel",model);
}
/**
* 获取创建表单页面
* @param model
* @return
*/
@GetMapping("/form")
public ModelAndView createForm(Model model){
model.addAttribute("user",new User(null,null,null));
model.addAttribute("title","创建用户");
return new ModelAndView("users/form","userModel",model);
}
/**
* 更新用户
* @param user
* @return
*/
@PostMapping
public ModelAndView saveOrUpdateUser(User user){
user=userRepository.save(user);
return new ModelAndView("redirect:/users");
}
/**
* 根据id删除用户
* @param id
* @return
*/
@GetMapping("/delete/{id}")
public ModelAndView delete(@PathVariable("id")Long id){
userRepository.delete(id);
return new ModelAndView("redirect:/users");
}
/**
* 根据id修改用户
* @param id
* @param model
* @return
*/
@GetMapping("/modify/{id}")
public ModelAndView modify(@PathVariable("id")Long id,Model model){
User user=userRepository.findOne(id);
model.addAttribute("user",user);
model.addAttribute("title","修改用户");
return new ModelAndView("users/form","userModel",model);
}
}
2.查看H2数据库
- 修改application.properties
#使用H2控制台spring.h2.console.enable=true
- 浏览器访问:
localhost:8080/h2-console
- JDBC URL:
jdbc:h2:mem:testdb
四、数据持久化到MySQL数据库
1. 修改application.properties
#DataSource
spring.datasource.url=jdbc:mysql://localhost/blog?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#JPA
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
2.运行项目
- 启动MySQL Server
- 创建blog数据库
- 运行项目
五、全文搜索
1.全文搜索简介
- 数据结构
- 结构化:指具有固定格式或有限长度的数据,如数据库,元数据等。
- 非结构化:指不定长或无固定格式的数据,如邮件,word文档等。
- 非结构化数据的检索
- 顺序扫描法(Serial Scanning)
- 全文搜索(Full-text Search):将非结构化的数据转为结构化的数据。
- 全文搜索实现原理
- 建立文本库
- 建立索引
- 执行搜索
- 过滤结果
- 基于Java的开源实现
- Lucene:开源全文搜索引擎
- ElasticSearch:基于Lucene的全文检索框架,实时搜索效率高
- Solr:类似ElasticSearch,基于zookeeper的分布式管理
2.ElasticSearch简介
- 高度可扩展的开源全文搜索和分析引擎
- 快速地、近实时地对大数据进行存储、搜索和分析
- 用来支撑有复杂的数据搜索需求的企业级应用
3.ElasticSearch的特点
- 分布式
- 高可用
- 多类型
- 多API
- 面向文档
- 异步写入
- 近实时
- 基于Lucene
- Apache协议
4.ElasticSearch核心概念
- 近实时:每隔n秒进行刷新,新创建的索引保存在文件系统中,在刷新的时候被存入。
- 集群:一个或多个节点的集合,保存应用的所有数据。每一个集群都有一个名称。
- 节点:一个单台服务器,用来保存数据,并参与整个集群的索引和操作。
- 索引:用来加快搜索速度、是所有文档的集合。
- 类型:根据文档的属性来划分类型。
- 文档:进行索引的基本单位,使用json格式表示。
- 分片:将索引分配到不同的节点中。
- 副本:为了防止数据丢失,增加吞吐量。
5.Elasticsearch与Spring Boot集成
- 配置环境
- Elasticsearch 2.4.4
- Spring Data Elasticsearch 2.1.3.RELEASE
- JNA 4.3.9 --->访问操作系统原生应用
- 修改build.gradle
//依赖关系
dependencies{
...
//添加 Spring Data ElasticSearch的依赖
compile('org.springframework.boot:spring-boot-starter-data-elasticsearch')
//添加JNA的依赖
compile('net.java.dev.jna:jna:4.3.0')
...
}
6.Elasticsearch实战
- 修改application.properties
# Elasticsearch服务地址
spring.data.elasticsearch.cluster-nodes=localhost:9300
# 设置连接超时时间
spring.data.elasticsearch.properties.transport.tcp.connect_timeout=120s
后台编码:
- 文档 EsBlog
- 资源库EsBlogRepository
- 资源库测试用例 EsBlogRepositoryTest
- 控制器 BlogController
EsBlog
package com.zhuyong.domain.es;
import org.springframework.data.elasticsearch.annotations.Document;
import javax.persistence.Id;
import java.io.Serializable;
/**
* @Author: zy
* @Description:
* @Date: 2018/6/19_14:19
**/
@Document(indexName = "blog",type = "blog") //文档
public class EsBlog implements Serializable{
private static final long serialVersionUID=1L;
@Id //主键
private String id;
private String title;
private String summary; //摘要
private String content; //正文内容
protected EsBlog(){ //JPA 规范要求,防止直接使用
}
public EsBlog(String title,String summary,String content){
this.title=title;
this.summary=summary;
this.content=content;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString(){
return String.format("EsBlog[id='%s',title='%s',summary='%s'],content='%s'",id,title,summary,content);
}
}
- EsBlogRepository
package com.zhuyong.repository.es;
import com.zhuyong.domain.es.EsBlog;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* @Author: zy
* @Description: EsBlog Repository 接口
* @Date: 2018/6/19_13:48
**/
public interface EsBlogRepository extends ElasticsearchRepository<EsBlog,String> {
/**
* @Author: zy
* @Description: 分页查询博客(去重)
* @Date: 2018/6/20_16:26
**/
Page<EsBlog> findDistinctEsBlogByTitleContainingOrSummaryContainingOrContentContaining(String title, String summary, String content, Pageable pageable);
}
- EsBlogRepositoryTest
package com.zhuyong.repository.es;
import com.zhuyong.domain.es.EsBlog;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @Author: zy
* @Description: EsBlogRepository接口测试
* @Date: 2018/6/20_16:29
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class EsBlogRepositoryTest {
@Autowired
private EsBlogRepository esBlogRepository;
@Before
public void initRepositoryData(){
//清除所有数据
esBlogRepository.deleteAll();
esBlogRepository.save(new EsBlog("登鹳雀楼","王之涣的登鹳雀楼",
"白日依山尽,黄河入海流。欲穷千里目,更上一层楼。"));
esBlogRepository.save(new EsBlog("相思","王维的相思",
"红豆生南国,春来发几枝。愿君多采撷,此物最相思。"));
esBlogRepository.save(new EsBlog("静夜思","李白的静夜思",
"床前明月光,疑是地上霜。举头望明月,低头思故乡。"));
}
@Test
public void findDistinctEsBlogByTitleContainingOrSummaryContainingOrContentContaining() throws Exception {
Pageable pageable=new PageRequest(0,20);
String title="思";
String summary="相思";
String content="相思";
Page<EsBlog> page=esBlogRepository.findDistinctEsBlogByTitleContainingOrSummaryContainingOrContentContaining(title,summary,content,pageable);
assertThat(page.getTotalElements()).isEqualTo(2);
System.out.println("----------------start 1");
for(EsBlog blog:page.getContent()){
System.out.println(blog.toString());
}
System.out.println("----------------end 1");
}
}
- BlogController
package com.zhuyong.controller;
import com.zhuyong.domain.es.EsBlog;
import com.zhuyong.repository.es.EsBlogRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @Author: zy
* @Description: Blog 控制器
* @Date: 2018/6/20_17:02
**/
@RestController
@RequestMapping("/blogs")
public class BlogController {
@Autowired
private EsBlogRepository esBlogRepository;
@GetMapping()
public List<EsBlog> list(@RequestParam(value="title") String title,
@RequestParam(value="summary") String summary,
@RequestParam(value="content") String content,
@RequestParam(value="pageIndex",defaultValue= "0") int pageIndex,
@RequestParam(value="pageSize",defaultValue = "10") int pageSize){
//数据在Test中初始化
Pageable pageable=new PageRequest(pageIndex,pageSize);
Page<EsBlog> page=esBlogRepository.findDistinctEsBlogByTitleContainingOrSummaryContainingOrContentContaining(title,summary,content,pageable);
return page.getContent();
}
}
上一篇: 如何给linux配置ip地址
下一篇: mysql-merge合并表_MySQL
推荐阅读
-
Laravel框架学习笔记(二)项目实战之模型(Models)
-
ASP.Net MVC OA项目笔记<二>
-
SpringMVC学习笔记(二)创建一个SpringMVC项目
-
【第二版】高仿Android网易云音乐企业级项目实战课程介绍
-
Android电商项目学习笔记(二)--主界面完成
-
spring boot 学习笔记(二):项目属性配置
-
Laravel框架学习笔记(二)项目实战之模型(Models)_PHP
-
Laravel框架学习笔记(二)项目实战之模型(Models)_PHP
-
Laravel框架学习笔记(二)项目实战之模型(Models)_php实例
-
springboot+mybatis+freemarker+shiro多模块项目搭建笔记(二)--集成mybatis plus