Springboot+JPA+Hibernate搭建后台服务
1 环境
1.1环境配置与搭建
1.2连接gitee进行版本控制
1.3 maven配置国内镜像
eclipse里的maven配置国内镜像
由于我下载的eclipse不自带配置文件,去网上找了一个配置文件进行更改。
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>/Users/syc/.m2/repository</localRepository>
<pluginGroups>
</pluginGroups>
<proxies>
</proxies>
<servers>
</servers>
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<profiles>
<profile>
<id>securecentral</id>
<repositories>
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>https://repo1.maven.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</settings>
1.3 pom.xml
poi-ooxml负责excel导出,kaptcha负责验证码生成
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.hxb</groupId>
<artifactId>task-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>task-1</name>
<description>task project</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2程序开发
2.1跨域
Spring CORS介绍
本人使用WebMvcConfigurer进行跨域处理
package com.hxb.task.util;
/**
*
* 全局跨域配置
*
* Created by macro on 2019/7/27.
*
*/
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class GlobalCorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") //.allowedOrigins("http://localhost:8090")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}
}
2.2权限控制
通过@Value获取application.yml配置文件中的配置项
package com.hxb.task.util;
import java.io.IOException;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import com.hxb.task.model.Function;
import com.hxb.task.model.User;
/**
* 权限过滤器
*
*/
@WebFilter(filterName = "SessionFilter", urlPatterns = "/*")
@Order(2)//用于控制过滤器的优先级
public class SessionFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionFilter.class);
/**无需权限验证的路径,以逗号隔开*/
@Value("${project.authorityUrl}")
private String authorityUrl;
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;;
String[] authorityUrls=authorityUrl.split(",");
String urlPath = request.getRequestURI();
LOGGER.debug("开始权限验证,路径:"+urlPath);
for(int i=0;i<authorityUrls.length;i++)
{
if(urlPath.startsWith(authorityUrls[i])){
LOGGER.debug("当前请求无需验证");
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}
HttpSession session = request.getSession();
if(session==null){
LOGGER.debug("session过期");
//未登录或者session过期
request.getRequestDispatcher("/unauthorized").forward(servletRequest, servletResponse);
return;
}
User user = (User)session.getAttribute("userSession");//从session中取user对象
List<Function> userFunctions = (List<Function>) session.getAttribute("userFunctions");//从session中取功能列表
if (user==null) {
LOGGER.debug("session过期,userSession为空");
request.getRequestDispatcher("/unauthorized").forward(servletRequest, servletResponse);
}
else{
try {
for(Function func : userFunctions){
if(func.getPath()!=null&&(urlPath.equals(func.getPath())||urlPath.startsWith(func.getPath()+"/")||urlPath.startsWith(func.getPath()+"?"))){
LOGGER.debug("通过权限验证");
filterChain.doFilter(servletRequest, servletResponse);
return;
}
}
} catch (Exception e) {
LOGGER.error("权限验证失败class SessionFilter:"+ e.getMessage(),e);
request.getRequestDispatcher("/forbidden").forward(servletRequest, servletResponse);
}
LOGGER.debug("用户进行了非功能权限内的操作!uri:" + urlPath);
request.getRequestDispatcher("/forbidden").forward(servletRequest, servletResponse);
}
}
public void init(FilterConfig arg0) throws ServletException {
LOGGER.info("session filter 初始化");
}
public void destroy() {
}
}
2.3日志配置
application.yml
logging:
#level 日志等级 指定命名空间的日志输出
level:
com.hxb.task: debug
#file 指定输出文件的存储路径
file: logs
#pattern 指定输出场景的日志输出格式
pattern:
console: "%d %-5level %logger : %msg%n"
file: "%d %-5level [%thread] %logger : %msg%n"
使用方法
private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
LOGGER.debug("xxx");
2.4验证码使用
application.yml
kaptcha:
border: "yes" # 是否有边框,默认为yes,可选yes、no
border.color: 105,179,90 #边框颜色
textproducer:
font:
color: blue # 验证码字体颜色
size: 30 # 文本字符大小
names: 宋体,楷体,微软雅黑 #文本字体样式
char:
length: 4 #验证码文本字符长度
image:
width: 120 # 图片宽度
height: 40 # 图片高度
session:
key: code # 存储session key
controller代码
@Autowired
private Producer captchaProducer = null;
@ResponseBody
@RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
public void getJCaptchaImage(HttpServletRequest request,HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
response.setContentType("image/jpeg");
//生成验证码
String capText = captchaProducer.createText();
session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);
//向客户端写出
BufferedImage bi = captchaProducer.createImage(capText);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(bi, "jpg", out);
try {
out.flush();
} finally {
out.close();
}
}
@ResponseBody
@RequestMapping(value = "/validate")
public Boolean login(String code, HttpServletRequest request) {
Boolean result = false;
String verifyCodeExpected = (String) request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
if (verifyCodeExpected.equals(code)) {
LOGGER.debug("验证成功"+verifyCodeExpected+"-"+code);
result=true;
}
else
{
LOGGER.debug("验证失败"+verifyCodeExpected+"-"+code);
}
return result;
}
2.5excel导入导出
2.6Controller
- application/x-www-form-urlencoded,这种情况的数据@RequestParam、@ModelAttribute、@RequestBody会导致无法接收。
- multipart/form-data,@RequestParam MultipateFile。(form表单里面有文件上传时,必须要指定enctype属性值为multipart/form-data,意思是以二进制流的形式传输文件。)
- application/json、application/xml等格式的数据,使用@RequestBody、@RequestParam来处理,同一个接口一般只使用一个RequestBody
package com.hxb.task.controller;
import com.hxb.task.api.CommonResult;
import com.hxb.task.model.Pos;
import com.hxb.task.service.PosService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
/**
* 职位管理Controller
* Created by macro on 2019/4/19.
*/
@Controller
@RequestMapping("/pos")
public class PosController {
@Autowired
private PosService posService;
private static final Logger LOGGER = LoggerFactory.getLogger(PosController.class);
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseBody
public CommonResult createPos(@RequestBody Pos pos) {
CommonResult commonResult;
try
{
posService.createPos(pos);
}
catch(DataIntegrityViolationException e)
{
LOGGER.error("职位名已存在:{}", pos);
return CommonResult.failed("职位名已存在");
}
catch(Exception e)
{
LOGGER.error("创建职位失败:", e);
return CommonResult.failed("操作失败");
}
commonResult = CommonResult.success(pos);
LOGGER.info("创建职位成功:{}", pos);
return commonResult;
}
@RequestMapping(value = "/update/{id}", method = RequestMethod.POST)
@ResponseBody
public CommonResult updatePos(@PathVariable("id") Integer id, @RequestBody Pos pos) {
CommonResult commonResult;
try
{
posService.updatePos(id, pos);
}
catch(Exception e)
{
LOGGER.error("更新职位失败:", e);
return CommonResult.failed("操作失败");
}
commonResult = CommonResult.success(pos);
LOGGER.debug("更新职位成功:{}", pos);
return commonResult;
}
@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
@ResponseBody
public CommonResult deletePos(@PathVariable("id") Integer id) {
try
{
posService.deletePos(id);
}
catch(DataIntegrityViolationException e)
{
LOGGER.debug("删除职位失败 ", e);
return CommonResult.failed("当前职位正在使用");
}
catch(Exception e)
{
LOGGER.debug("删除职位失败 ", e);
return CommonResult.failed("操作失败");
}
LOGGER.debug("删除职位成功 :id={}", id);
return CommonResult.success(null);
}
@RequestMapping(value = "/list", method = RequestMethod.GET)
@ResponseBody
public CommonResult<Page<Pos>> listPoss(HttpServletRequest request,@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,@RequestParam(value = "posId",required=false) String posIds,
@ModelAttribute Pos pos) {
Page<Pos> posList = posService.listPoss(pageNum-1, pageSize,pos);
return CommonResult.success(posList);
}
@RequestMapping(value = "/listAll", method = RequestMethod.GET)
@ResponseBody
public CommonResult<List<Pos>> listPosAll(@ModelAttribute Pos pos) {
List<Pos> posList = posService.listPosAll(pos);
return CommonResult.success(posList);
}
@RequestMapping(value = "/id/{id}", method = RequestMethod.GET)
@ResponseBody
public CommonResult<Pos> pos(@PathVariable("id") Integer id) {
return CommonResult.success(posService.getPos(id));
}
}
2.7Service
package com.hxb.task.service;
import com.hxb.task.model.Pos;
import java.util.List;
import org.springframework.data.domain.Page;
public interface PosService {
void createPos(Pos pos);
void updatePos( Integer id,Pos pos);
void deletePos(Integer id);
Page<Pos> listPoss(int pageNum, int pageSize,Pos pos);
List<Pos> listPosAll(Pos pos);
Pos getPos(Integer id);
}
Transactional进行事务控制,向JpaRepository中传入Pageable,可进行分页,返回Page对象。
package com.hxb.task.service.impl;
import com.hxb.task.api.Menu;
import com.hxb.task.dao.FunctionDao;
import com.hxb.task.dao.PosDao;
import com.hxb.task.service.PosService;
import com.hxb.task.util.SystemServices;
import com.hxb.task.model.Function;
import com.hxb.task.model.Pos;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Resource;
/**
* TPosService实现类
* Created by macro on 2019/4/19.
*/
@Service
public class PosServiceImpl implements PosService {
@Resource
PosDao posDao;
@Resource
FunctionDao functionDao;
@Resource(name="SystemServices")
SystemServices systemServices;
public Page<Pos> listPoss(int pageNum, int pageSize, Pos pos) {
Page<Pos> result =null;
Pageable pageable = PageRequest.of(pageNum, pageSize, Sort.Direction.ASC, "posId");
result = posDao.listPoss(pos,pageable);
return result;
}
public List<Pos> listPosAll( Pos pos) {
List<Pos> result =null;
result = posDao.listPosAll(pos);
return result;
}
public Pos getPos(Integer id) {
Optional<Pos> pos= posDao.findById(id);
return pos.get();
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public void createPos(Pos pos) {
posDao.save(pos);
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public void updatePos( Integer id,Pos pos) {
Optional<Pos> s = posDao.findById(id);
Pos old = s.get();
old.setPosName(pos.getPosName());
old.setPercent(pos.getPercent());
old.setMemo(pos.getMemo());
old.setScored(pos.getScored());
posDao.save(old);
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public void deletePos(Integer id) {
posDao.deleteById(id);
}
}
2.8Dao
配置application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/task?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
hikari: # Hikari 数据源专用配置
maximum-pool-size: 20
minimum-idle: 5
jpa:
database: MYSQL
database-platform: org.hibernate.dialect.MySQL57Dialect
#自动建表,表类型innodb,也可用MySQL5Dialect
hibernate:
ddl-auto: update
show-sql: true
1.通过:#{#pos.posName} =null or s.posName like %:#{#pos.posName}% 语句,当变量为空时,不当做查询条件使用。
2.传入Pageable,可进行分页,返回Page对象。
3.继承JpaRepository,JpaRepository功能
package com.hxb.task.dao;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.hxb.task.model.Pos;
@Repository
public interface PosDao extends JpaRepository<Pos, Integer> {
@Query(value = "select s from Pos s where s.posId=:posId")
Pos getPos(@Param("posId") Integer posId);
@Query(value = "select s from Pos s where ( :#{#pos.posName} =null or s.posName like %:#{#pos.posName}% ) ")
Page<Pos> listPoss(@Param("pos") Pos pos, Pageable pageable);
@Query(value = "select s from Pos s where ( :#{#pos.posName} =null or s.posName like %:#{#pos.posName}% ) ")
List<Pos> listPosAll(@Param("pos") Pos pos);
/* nativeQuery =true的情况下可直接执行sql语句
@Query(value = "SELECT distinct a.* FROM t_function a LEFT JOIN role_function b ON a.func_no = b.functions_func_no LEFT JOIN user_role c ON b.roles_role_id = c.roles_role_id WHERE c.users_user_id = ?1 ORDER BY func_no ASC",nativeQuery = true)
List<Function> getFunctionList(Integer userId);
*/
/* jpql中存在in的情况
@Query(value = "select s from Score s where ( :#{#score.year} =null or s.year = :#{#score.year}) and"
+ "( :#{#score.quarter} =null or s.quarter = :#{#score.quarter}) and "
+ "( :#{#score.status} =null or s.status = :#{#score.status}) and s.org.orgId in (?1) ")
List<Score> listScoreAll(@Param("orgs") List<Integer> orgs,@Param("score") Score score);
*/
}
来源:CSDN
作者:灬弑月
链接:https://blog.csdn.net/u013394881/article/details/104898509