首先,添加maven依赖,完整的pom文件如下:

 <?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hui</groupId>
<artifactId>SpringBoot22</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBoot22</name>
<description>Demo project for Spring Boot</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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

  接着,我们先编写自定义的Realm类(MyJbdcRealm)

 package com.hui.SpringBoot22.realm;

 import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.JdbcUtils; import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set; public class MyJdbcRealm extends AuthorizingRealm { protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
protected static final String DEFAULT_USER_ROLES_QUERY = "select role_name from user_roles where username = ?";
protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
protected DataSource dataSource;
protected String authenticationQuery = DEFAULT_AUTHENTICATION_QUERY;
protected String userRolesQuery = DEFAULT_USER_ROLES_QUERY;
protected String permissionsQuery = DEFAULT_PERMISSIONS_QUERY;
protected boolean permissionsLookupEnabled = false; public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
} public void setAuthenticationQuery(String authenticationQuery) {
this.authenticationQuery = authenticationQuery;
} public void setUserRolesQuery(String userRolesQuery) {
this.userRolesQuery = userRolesQuery;
} public void setPermissionsQuery(String permissionsQuery) {
this.permissionsQuery = permissionsQuery;
} public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
this.permissionsLookupEnabled = permissionsLookupEnabled;
} protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm.");
}
Connection conn = null;
SimpleAuthenticationInfo info = null;
try {
conn = dataSource.getConnection();
String password = null;
password = getPasswordForUser(conn, username);
if (password == null) {
throw new UnknownAccountException("No account found for user [" + username + "]");
}
info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
} catch (SQLException e) {
final String message = "There was a SQL error while authenticating user [" + username + "]";
throw new AuthenticationException(message, e);
} finally {
JdbcUtils.closeConnection(conn);
}
return info;
} private String getPasswordForUser(Connection conn, String username) throws SQLException {
String result = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(authenticationQuery);
ps.setString(1, username);
rs = ps.executeQuery();
boolean foundResult = false;
while (rs.next()) {
if (foundResult) {
throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
}
result = rs.getString(1);
foundResult = true;
}
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(ps);
}
return result;
} @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
}
String username = (String) getAvailablePrincipal(principals);
Connection conn = null;
Set<String> roleNames = null;
Set<String> permissions = null;
try {
conn = dataSource.getConnection();
roleNames = getRoleNamesForUser(conn, username);
if (permissionsLookupEnabled) {
permissions = getPermissions(conn, username, roleNames);
}
} catch (SQLException e) {
final String message = "There was a SQL error while authorizing user [" + username + "]";
throw new AuthorizationException(message, e);
} finally {
JdbcUtils.closeConnection(conn);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
info.setStringPermissions(permissions);
return info;
} protected Set<String> getRoleNamesForUser(Connection conn, String username) throws SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
Set<String> roleNames = new LinkedHashSet<String>();
try {
ps = conn.prepareStatement(userRolesQuery);
ps.setString(1, username);
rs = ps.executeQuery();
while (rs.next()) {
String roleName = rs.getString(1);
if (roleName != null) {
roleNames.add(roleName);
}
}
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(ps);
}
return roleNames;
} protected Set<String> getPermissions(Connection conn, String username, Collection<String> roleNames) throws SQLException {
PreparedStatement ps = null;
Set<String> permissions = new LinkedHashSet<String>();
try {
ps = conn.prepareStatement(permissionsQuery);
for (String roleName : roleNames) {
ps.setString(1, roleName);
ResultSet rs = null;
try {
rs = ps.executeQuery();
while (rs.next()) {
String permissionString = rs.getString(1);
String[] permissionNames = permissionString.split(",");
permissions.addAll(Arrays.asList(permissionNames));
}
} finally {
JdbcUtils.closeResultSet(rs);
}
}
} finally {
JdbcUtils.closeStatement(ps);
}
return permissions;
}
}

MyJdbcRealm类就是从shiro中原有的JdbcRealm类copy来的,去掉了与密码盐(salt)有关的部分。

我在数据库的权限表中添加的权限字段值为 “user:add,user:delete,user:update,user:select,user:updateRole” 的格式,而shiro中原有的JdbcRealm中会将这一长串当成一种权限来看,在 MyJdbcRealm 类中改写了 JdbcRealm中的 getPermissions(Connection conn, String username, Collection<String> roleNames) 方法(具体看159-161行)来使权限字段的值为 5种 不同的权限。

当然,你也可以在自定义的 Realm 类中重写 doGetAuthorizationInfo(PrincipalCollection principals) 方法,来实现自己的权限管理。

  接着,编写shiro的配置类(ShiroConfiguration)

 package com.hui.SpringBoot22;

 import com.hui.SpringBoot22.realm.MyJdbcRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; import javax.sql.DataSource;
import java.util.*; @Configuration
public class ShiroConfiguration { @Autowired
private DataSource dataSource; @Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//配置login页、登陆成功页、没有权限页
shiroFilterFactoryBean.setLoginUrl("/");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403"); //配置访问权限(顺序执行拦截)
// “/**” 放到最下面,如果将("/**","authc")放到("/userLogin","anon")的上面
// 则“/userLogin”可能会被拦截
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/logout","logout");
filterChainDefinitionMap.put("/userLogin","anon");
filterChainDefinitionMap.put("/403","roles");
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
} @Bean(name = "securityManager")
public SecurityManager securityManager(@Qualifier("myJdbcRealm")MyJdbcRealm myJdbcRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myJdbcRealm);
return securityManager;
} @Bean(name = "myJdbcRealm")
public MyJdbcRealm myJdbcRealm(@Qualifier("credentialsMatcher") HashedCredentialsMatcher credentialsMatcher,
@Qualifier("dataSource") DataSource dataSource){
MyJdbcRealm myJdbcRealm = new MyJdbcRealm();
//打开shiro的权限 (默认为false) (不开启则不会检查权限 --> 点击“修改”,不管有没有权限都能进行跳转)
myJdbcRealm.setPermissionsLookupEnabled(true);
//设置datasource
myJdbcRealm.setDataSource(dataSource);
//设置密码加密器
myJdbcRealm.setCredentialsMatcher(credentialsMatcher);
//设置登陆验证sql语句
String sql = "select password from test_user where username = ?";
myJdbcRealm.setAuthenticationQuery(sql);
//设置权限验证sql语句
String permissionSql = "select permission from permissions where role_name = ?";
myJdbcRealm.setPermissionsQuery(permissionSql);
return myJdbcRealm;
} //设置加密算法为MD5。加密次数为1
@Bean(name = "credentialsMatcher")
public HashedCredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5");
credentialsMatcher.setHashIterations(1);
return credentialsMatcher;
} /**
* 开启aop注解支持 -- 借助SpringAOP扫描使用shiro注解的类
* (不开启则不能扫描到shiro的@RequiresPermissions等注解)
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
} //配置无权限异常处理,跳转到403
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException", "403");
r.setExceptionMappings(mappings); // None by default
r.setDefaultErrorView("error"); // No default
r.setExceptionAttribute("ex"); // Default is "exception"
return r;
} }

  上面代码中有几个需要注意的点:

第一点:是再定义的名为“securityManager”的 Bean 中,使用的是 DefaultWebSecurityManager 这个类,而不是 DefaultSecurityManager(使用DefaultSecurityManager类会报错),前者是 org.apache.shiro.web.mgt 包下的,与web有关;后者是 org.apache.shiro.mgt 包下的。

第二点:开启aop注解支持 -- 借助SpringAOP扫描使用shiro注解的类,开启之后可以扫描到 Controller 类上的shiro注解(例如:@RequiresPermissions、@RequiresRoles等

第三点:配置无权限异常处理,这样就会拦截到没有权限的用户,然后跳转到403页面(

  这里配置无权限异常处理是为了配合shiro注解。

  如果不想使用shiro注解,也可以不配置该异常处理,直接在拦截链“filterChainDefinitionMap”中配置 -- 例如:/userList= roles["admin","admin1"] --> 表明访问路径 /userList 需要同时具备“admin”和“admin1”的角色,不合条件则403;             另一种与角色拦截相似:权限拦截 -- /userList= perms["user:select"]

第四点:在名为 “myJdbcRealm” 的Bean中,设置登陆验证与权限验证的sql查询语句,方法分别是 setAuthenticationQuery("select password from test_user where username = ?") 、 setPermissionsQuery("select permission from permissions where role_name = ?")

之所以执行这两个setXxx()方法,是因为我这里的实体类对应生成的表名、字段名与shiro默认的不一致(如果你想使用shiro默认的,那么你就需要按照shiro源码中的sql语句来设置实体生成的表名、字段名与shiro默认的一致即可)

  接下来,编写实体类

User类

 package com.hui.SpringBoot22.pojo;

 import javax.persistence.*;

 @Entity
@Table(name = "test_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)//默认为AUTO,这里设置为自增
private Long id;
@Column(name = "username",length = 50)
private String username;
@Column(name = "password",length = 50)
private String password; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
}

Role类

 package com.hui.SpringBoot22.pojo;

 import javax.persistence.*;

 @Entity
@Table(name = "user_roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username",length = 50)
private String username;
@Column(name = "role_name",length = 50)
private String roles; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getRoles() {
return roles;
} public void setRoles(String roles) {
this.roles = roles;
}
}
Permission类
 package com.hui.SpringBoot22.pojo;

 import javax.persistence.*;

 @Entity
@Table(name = "permissions")
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "role_name",length = 50)
private String roleName;
@Column(name = "permission",length = 120)
private String permissions; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getRoleName() {
return roleName;
} public void setRoleName(String roleName) {
this.roleName = roleName;
} public String getPermissions() {
return permissions;
} public void setPermissions(String permissions) {
this.permissions = permissions;
}
}

这里就不多说了,主要注意的就是对应的表名、字段名要与 ShiroConfiguration 类中的sql语句的表名、字段名一致。

  接下来是Repository编写,直接看代码好了

 package com.hui.SpringBoot22.repository;

 import com.hui.SpringBoot22.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import javax.transaction.Transactional; public interface UserRepository extends JpaRepository<User,Long> {
User findUserById(Long id); @Transactional
@Modifying
@Query("update User set username=?2,password=?3 where id=?1")
int updateUserById(Long id,String username,String password); @Transactional
@Modifying
@Query("delete from User where id=?1")
void deleteUserById(Long id);
}

这里继承了JpaRepository类,就不用再类上加Spring注解来将其注入(因为 JpaRepository 类上有一个@NoRepositoryBean注解,原理咱不懂!!!

select、delete之类的语句 Jpa 已经封装了一部分方法,我们可以直接调用,如 save(S entity)、delete(T entity)等

如果Jpa中封装的不能满足需求,那就自己写啦

像上面的在 UserRepository 类中添加一个方法,然后再方法上加上@Query注解,里面有个value属性,用来指定编写的sql语句  -->  如:@Query(value="update ...")

值得注意的是,在 @Query 注解中的 sql 语句对应的表名应写 实体类名(上面代码中本人写的就是实体类 User );关于sql中的字段是不是需要用实体类属性名,有兴趣的朋友可以自己试一下。

如果觉得别扭,可以在@Query注解中编写 nativeQuery 属性,使其值为 true ,这样 Jpa 就能识别原生 sql 了   -->

例子:  @Query(nativeQuery = true,
   value="select r.id,r.username,r.role_name from user_roles u left join user_roles r on u.username=r.username where u.id=?1")
     Role findRoleByUserid(Long id);

最后,如果是insert、delete、update之类的语句,还要在方法上面加上@Modifying和@Transactional注解(等大佬帮我解惑ing...

  接着,再贴一下 controller 的代码

 package com.hui.SpringBoot22.controller;

 import com.hui.SpringBoot22.pojo.User;
import com.hui.SpringBoot22.repository.UserRepository;
import com.hui.SpringBoot22.utils.Md5;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import java.util.List;
import java.util.Map; @Controller
public class UserController {
@Autowired
private UserRepository userRepository; @RequestMapping("/")
public String toLogin(){
return "login";
} @RequestMapping("/userLogin")
public String userLogin(String username, String password, Map<String,Object> map){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try{
subject.login(token);
map.put("loginName",username);
}catch(Exception e){
map.put("msg","登陆失败");
return "login";
}
return "forward:userList";
} @RequestMapping("/userList")
@RequiresPermissions("user:select")
public String list(Map<String,Object> map){
List<User> users = userRepository.findAll();
map.put("userList",users);
return "userList";
} @RequestMapping("/toUserAdd")
public String toAdd(){
return "userAdd";
} @RequestMapping("/userAdd")
@RequiresPermissions("user:add")
public String userAdd(User user){
user.setPassword(Md5.md5(user.getPassword()));
userRepository.save(user);
return "forward:userList";
} @RequestMapping("/toUserEdit")
public String toEdit(Long id,Map<String,Object> map){
User user = userRepository.findUserById(id);
map.put("user",user);
return "userEdit";
} @RequestMapping("/userEdit")
@RequiresPermissions("user:update")
public String userEdit(Long id,String username,String password){
password = Md5.md5(password);
userRepository.updateUserById(id,username,password);
return "forward:userList";
} @RequestMapping("/userDelete")
@RequiresPermissions("user:delete")
public String deleteUser(Long id){
userRepository.deleteUserById(id);
return "forward:userList";
}
}

@RequiresPermissions注解是验证用户权限

@RequiresRoles注解是验证用户角色(这个在RoleController中用到,这里没有贴出来

  然后,再看一部分使用 thymeleaf 的HTML代码

 <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="margin-left: 30%">
<form action="/roleUpdate" method="post">
<input type="hidden" name="id" th:value="${role.id}"/>
用 户 名:<input name="username" type="text" th:value="${role.username}"/><br/><br/>
选择角色:<input style="margin-left: 8px;" type="radio" name="roles"
th:each="roleName,roleNameStat:${roleNameList}"
th:value="${roleName}"
th:text="${roleName}"
th:attr="checked=${roleName==role.roles?true:false}"
/><br/><br/>
<input type="submit" value="提交"/>
</form>
</div>
</body>
</html>

老实说,第一次使用 thymeleaf 真的不大习惯,总是写成常规的 HTML 代码

上面也没什么好说的,也就一个下拉框的遍历(

                      th:text 表示文本值, th:value 表示value值,th:attr 表示是否选中状态,

                      th:each 就是遍历后台传来的 list 集合  -->  roleName 代表每一个 list 集合元素,roleNameStat.index 代表着该元素的下标

                      )

  最后,再看一下配置文件 application.properties

 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=xxx
spring.datasource.password=xxx spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.database=mysql spring.thymeleaf.cache=false
spring.thymeleaf.mode=HTML

这个地方有一个坑,就是如果我们设置 spring.jpa.hibernate.ddl-auto=update,就不会执行 resources 目录下的 import.sql 文件等

根据官方文档来说,如果需要执行 resources 目录下的 import.sql 文件,就必须设置 spring.jpa.hibernate.ddl-auto 的值为 create 或者 create-drop

还一种办法就是不使用 spring.jpa.hibernate.ddl-auto ,直接在 resources 目录下添加 schema.sql 和 data.sql 文件(schema.sql用来执行DDL语句,data.sql用来执行DML语句)

  还有少部分代码和 HTML 就不贴出来了,有兴趣的可以去下载源代码看看。

  项目默认登陆用户   ==>   用户名:lmh,密码:123

  项目GitHub地址https://github.com/Lmh115/SpringBoot

SpringBoot2.1.6 + Shiro1.4.1 + Thymeleaf + Jpa整合练习的更多相关文章

  1. SpringBoot2.0+Mybatis-Plus3.0+Druid1.1.10 一站式整合

    SpringBoot2.0+Mybatis-Plus3.0+Druid1.1.10 一站式整合 一.先快速创建一个springboot项目,其中pom.xml加入mybatis-plus 和druid ...

  2. Spring Boot 揭秘与实战(二) 数据存储篇 - JPA整合

    文章目录 1. 环境依赖 2. 数据源 3. 脚本初始化 4. JPA 整合方案一 通过继承 JpaRepository 接口 4.1. 实体对象 4.2. DAO相关 4.3. Service相关 ...

  3. 【SpringBoot】SpringBoot/MyBatis/MySql/thymeleaf/Log4j整合工程

    工程下载地址:https://files.cnblogs.com/files/xiandedanteng/MMSpringWeb20191027-1.rar 工程目录结构如图: 1.创建工程 有些网文 ...

  4. SpringBoot(三)thymeleaf+JPA+MySql

    接着上一节的 第一步:在pom文件中加入以下代码: <!--JPA--> <dependency> <groupId>org.springframework.boo ...

  5. spring boot(十五)spring boot+thymeleaf+jpa增删改查示例

    快速上手 配置文件 pom包配置 pom包里面添加jpa和thymeleaf的相关包引用 <dependency> <groupId>org.springframework.b ...

  6. SpringBoot2.0 基础案例(09):集成JPA持久层框架,简化数据库操作

    一.JAP框架简介 JPA(Java Persistence API)意即Java持久化API,是Sun官方在JDK5.0后提出的Java持久化规范.主要是为了简化持久层开发以及整合ORM技术,结束H ...

  7. Spring 4 mvc+shiro+thymeleaf+JPA(Hibernate)+MySql eclipse项目模板

    本模板基本配制为:spring 4.3.8+thymeleaf 3.0.3 +hibernate 5.5.5 + mysql 5.7 IDE:eclipse 运行环境为:Tomcat 8.0.28 项 ...

  8. Thymeleaf+Spring整合

    前言 这个教程介绍了Thymeleaf与Spring框架的集成,特别是SpringMvc框架. 注意Thymeleaf支持同Spring框架的3.和4.版本的集成,但是这两个版本的支持是封装在thym ...

  9. spring与jpa整合 简化persistence.xml配置文件 使用属性文件 数据源dbcp访问数据库

    ===========appliction.xml配置文件======================= <?xml version="1.0" encoding=" ...

随机推荐

  1. 【Linux】Linux下设备网卡以及硬件管理等

    这是Linux下网络硬件管理的基础知识,虽然平时用到的可能比软件的少一点,但是作为基础命令,还是需要记住,以免用时又得查询. 本文参考官方文档:https://wiki.ubuntu.com.cn/% ...

  2. UbuntuServer添加软件源列表

    要使用Ubuntu前,我们一般都要先做好工具!特别是对于安装这一块~~~~ 1.配置前,先做个配置文件的备份: $sudo cp /etc/apt/sources.list /etc/apt/sour ...

  3. orm单表操作

    二.orm简介 ORM:object relation mapping (ORM是“对象-关系-映射”的简称) MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦, ...

  4. Java开发桌面程序学习(三)——基于Jfoenix库的JFXDialog封装仿Android对话框的工具DialogBuilder

    对话框的封装使用 最近写了个JFXUtils,DialogBuilder也是包含在里面了 JFXUtils的Github 前言 登录需要弹出登录对话框,但是,Jfoenix库使用对话框比较难受,还得动 ...

  5. MyBatis中二级缓存和延时加载同时开启的问题

    首先,二级缓存默认不开启! 要配置 <setting name="cacheEnabled" value="true"/> 在MyBatis中:一级 ...

  6. Spring Cloud Stream整合RabbitMQ

    简介 Spring Cloud Stream是一个构建消息驱动微服务的框架,应用程序通过input(相当于consumer).output(相当于producer)来与Spring Cloud Str ...

  7. .Net for Spark 实现 WordCount 应用及调试入坑详解

    .Net for Spark 实现WordCount应用及调试入坑详解 1.    概述 iNeuOS云端操作系统现在具备物联网.视图业务建模.机器学习的功能,但是缺少一个计算平台产品.最近在调研使用 ...

  8. Angular4.0从入门到实战打造在线竞拍网站学习笔记之二--路由

    Angular4.0基础知识之组件 Angular4.0基础知识之路由 Angular4.0依赖注入 Angular4.0数据绑定&管道 路由 简介 接下来学习路由的相关知识 本来是不准备写下 ...

  9. K Balanced Teams CodeForces - 1133E (Dp)

    题意: 给出 n 个数,选取其中若干个数分别组成至多 k 组,要求每组内最大值与最小值的差值不超过5,求最后被选上的总人数. 题解: 将a[1∼n] 从小到大排序, f[i][j] 表示到第 i 个数 ...

  10. HDU 3183:A Magic Lamp(RMQ)

    http://acm.hdu.edu.cn/showproblem.php?pid=3183 题意:给出一个数,可以删除掉其中m个字符,要使得最后的数字最小,输出最后的数字(忽略前导零). 思路:设数 ...