栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Spring Boot】Spring Boot Security REST + JPA + Hibernate + MySQL 示例 | 接口安全验证

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Spring Boot】Spring Boot Security REST + JPA + Hibernate + MySQL 示例 | 接口安全验证

文章目录
  • 演示工具版本
  • 项目结构
  • Spring Boot 默认的验证方式
  • Maven 文件
  • application.properties
  • MySQL 表和 JAVA 实体
  • 创建 DAO 用于用户认证
  • 实现 UserDetailsService
  • 实现 BasicAuthenticationEntryPoint
  • Security 配置
  • 创建 DAO 用于 CRUD 操作
  • 创建带安全验证 CURD 操作的 Service
  • 创建 Controller 用于 CURD 操作
  • 使用 SpringApplication 创建主类
  • 使用 RestTemplate 创建客户端
  • 运行应用程序
    • 1. 使用Eclipse
    • 2. 使用Maven命令
    • 3. 使用可执行的JAR
  • 参考文献
  • 源码下载

本页将介绍Spring Boot Security REST + JPA + Hibernate + MySQL CRUD的例子。

当我们使用Spring Boot创建应用程序时,我们只需写几行代码就可以包含网络请求、安全验证和数据库连接等功能。

如果Spring Boot在类路径中获得Spring Security,那么它将自动执行与安全有关的配置。

同样,如果Spring Boot在其类路径中获得Spring Web和Spring Data,那么Spring Boot会自动执行Spring Web和数据库连接相关的配置。

在Spring Security方面,Spring Boot默认配置了内存中的认证,使用一个用户和随机密码,在每次服务器重启后都会改变。我们可以在控制台中获得默认密码。

在我们的例子中,我们将在数据库中保存用户认证相关的数据,所以我们必须覆盖Spring Boot的默认安全配置。我们将创建一个带有@Configuration和@EnableWebSecurity注释的安全配置文件。

为了覆盖HttpSecurity,我们的安全配置类需要扩展WebSecurityConfigurerAdapter类并覆盖configure()方法。

为了启用方法级别的安全,用@EnableGlobalMethodSecurity来注释安全配置类。

为了使用数据库对用户进行认证和授权,我们需要实现UserDetailsService接口。

我们将在我们的REST网络服务例子中处理创建(CREATE)、读取(READ)、更新(UPDATe)和删除(DELETE)操作,简称CRUD。

让我们一步一步地讨论这个完整的例子。

演示工具版本
  1. Java 8
  2. Spring Boot 1.5.3.RELEASE
  3. Maven 3.3
  4. MySQL 5.5
  5. Eclipse Mars
项目结构

Spring Boot 默认的验证方式

如果spring security在类路径中,那么我们的spring boot web应用程序默认会自动使用基本认证来保证安全。

一个默认的用户名 "user "和随机密码将在服务器启动时显示在控制台中,可用于登录验证。

密码在控制台显示如下。

Using default security password: 7e9850aa-d985-471a-bae1-25d741d4da23 

上述密码是随机的,并且在服务器重启时改变。默认情况下,spring使用内存认证,单用户命名为 “user”。找到这些配置。

1. 要在spring boot应用程序中启用spring security,只需在maven或gradle文件中使用以下spring-boot配置。

spring-boot-starter-security 

2. 为了改变默认密码,spring boot提供了security.user.password属性,需要在application.properties中进行配置,如下所示。

security.user.password= concretepage 

现在我们可以使用user/concretepage的凭证登录应用程序。其他安全属性也可以通过SecurityProperties在application.properties中使用security.*前缀来改变,如下所示。

security.basic.enabled: 启用基本认证。默认值为true。

security.basic.path: 配置需要安全验证的路径。我们需要提供逗号分隔的路径。

security.enable-csrf: 启用和禁用CSRF。默认值为false。

security.require-ssl: 启用和禁用SSL。默认值为false。

security.sessions: 默认值是无状态。值可以是总是(always)、从不(never)、如果需要(if_required)、无状态(stateless)。

security.user.name: 配置用户名。默认用户是user。

security.user.password: 配置密码。

security.user.role: 它配置了角色。默认的角色是USER。

3. 如果我们已经微调了我们的日志配置,那么为了打印默认的随机密码,我们需要在application.properties中配置以下属性,级别为INFO。

logging.level.org.springframework.boot.autoconfigure.security= INFO 

4. 默认情况下,静态路径是不做安全验证的,如/cssfavicon.ico。

5. 如HSTS、XSS、CSRF、缓存等功能在spring security中是默认提供的。

上述属性可以使用security.*来打开和关闭,但如果我们想在数据库中使用用户名和密码,那么我们需要使用UserDetailsService。

为了控制安全相关的配置,我们可以创建一个安全配置类,它将扩展WebSecurityConfigurerAdapter,然后覆盖configure()方法。这个类将被注解为@Configuration和@EnableWebSecurity。

如果我们想启用方法级别的安全,该类将被注解为@EnableGlobalMethodSecurity。

Maven 文件

pom.xml



	4.0.0
	com.concretepage
	spring-boot-demo
	0.0.1-SNAPSHOT
	jar
	spring-demo
	Spring Boot Demo Project
	
		org.springframework.boot
		spring-boot-starter-parent
		1.5.3.RELEASE
	
	
		1.8
	
	
	    
		 org.springframework.boot
		 spring-boot-starter-web
	    
	    
		 org.springframework.boot
		 spring-boot-starter-security
	    		
	    
		 org.springframework.boot
		 spring-boot-starter-data-jpa
	    	
	    
		 mysql
		 mysql-connector-java
	    	 
    	    
                 org.springframework.boot
                 spring-boot-devtools
                 true
             
	 
	
	   
	 	
	        	org.springframework.boot
			spring-boot-maven-plugin
		
	   
	
 

当Spring Boot应用程序在类路径中找到任何JAR,那么Spring Boot会自动配置所需的设置。

spring-boot-starter-web: 自动配置web应用程序设置。

spring-boot-starter-security: 自动配置安全相关设置。

spring-boot-starter-data-jpa: 自动配置与数据库连接相关的设置。

application.properties

在Spring Boot中,要配置数据库相关属性、hibernate和日志,我们需要使用application.properties或application.yml。这些文件会被Spring Boot自动读取。

application.properties

#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/concretepage
spring.datasource.username=root
spring.datasource.password=
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-idle=20
spring.datasource.tomcat.min-idle=15

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.id.new_generator_mappings = false
spring.jpa.properties.hibernate.format_sql = true

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

#Security Configuration---
#security.user.password= concretepage
#prints default password---
#logging.level.org.springframework.boot.autoconfigure.security= INFO 

使用spring.datasource.*来配置数据源相关属性。使用spring.jpa.properties.*来配置JPA相关属性。

在我们的例子中,我们正在使用JPA和hibernate。

MySQL 表和 JAVA 实体

Database Schema

CREATE DATAbase IF NOT EXISTS `concretepage` ;
USE `concretepage`;
-- Dumping structure for table concretepage.articles
CREATE TABLE IF NOT EXISTS `articles` (
  `article_id` int(5) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `category` varchar(100) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.articles: ~3 rows (approximately)
INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES
	(1, 'Java Concurrency', 'Java'),
	(2, 'Hibernate HQL ', 'Hibernate'),
	(3, 'Spring MVC with Hibernate', 'Spring');
-- Dumping structure for table concretepage.users
CREATE TABLE IF NOT EXISTS `users` (
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `full_name` varchar(100) NOT NULL,
  `role` varchar(50) NOT NULL,
  `country` varchar(100) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.users: ~2 rows (approximately)
INSERT INTO `users` (`username`, `password`, `full_name`, `role`, `country`, `enabled`) VALUES
	('mukesh', '$2a$10$N0eqNiuikWCy9ETQ1rdau.XEELcyEO7kukkfoiNISk/9F7gw6eB0W', 'Mukesh Sharma', 'ROLE_ADMIN', 'India', 1),
	('tarun', '$2a$10$QifQnP.XqXDW0Lc4hSqEg.GhTqZHoN2Y52/hoWr4I5ePxK7D2Pi8q', 'Tarun Singh', 'ROLE_USER', 'India', 1); 

我们有两个表users和articles。

在users表中,我们保存与用户有关的信息,在articles表中,我们保存与文章有关的信息。

我们正在使用BCrypt密码编码方案。

找到一个简单的主类,可以用来生成BCrypt密码。

Main.java

package com.concretepage;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class Main {
	public static void main(String[] args) {
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		System.out.println(encoder.encode("m123"));
	}
}  

对于上述数据库模式中给定的两个表,请找到java实体。

UserInfo.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="users")
public class UserInfo implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@Column(name="username")
	private String userName;
	@Column(name="password")
	private String password;
	@Column(name="role")	
	private String role;
	@Column(name="full_name")	
	private String fullName;
	@Column(name="country")	
	private String country;
	@Column(name="enabled")	
	private short enabled;
	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;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public String getFullName() {
		return fullName;
	}
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public short getEnabled() {
		return enabled;
	}
	public void setEnabled(short enabled) {
		this.enabled = enabled;
	}
} 

Article.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private int articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public int getArticleId() {
		return articleId;
	}
	public void setArticleId(int articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
}  
创建 DAO 用于用户认证

在我们的例子中,我们没有使用Spring Boot默认的内存认证。我们将在MySQL数据库中存储用户认证相关的信息,并使用Hibernate访问它们。所以我们要创建一个DAO方法来返回给定用户名的用户信息。

IUserInfoDAO.java

package com.concretepage.dao;
import com.concretepage.entity.UserInfo;
public interface IUserInfoDAO {
     UserInfo getActiveUser(String userName);
} 

UserInfoDAO.java

package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.UserInfo;
@Repository
@Transactional
public class UserInfoDAO implements IUserInfoDAO {
	@PersistenceContext	
	private EntityManager entityManager;
	public UserInfo getActiveUser(String userName) {
		UserInfo activeUserInfo = new UserInfo();
		short enabled = 1;
		List list = entityManager.createQuery("SELECT u FROM UserInfo u WHERe userName=? and enabled=?")
				.setParameter(1, userName).setParameter(2, enabled).getResultList();
		if(!list.isEmpty()) {
			activeUserInfo = (UserInfo)list.get(0);
		}
		return activeUserInfo;
	}
} 

Spring @Transactional注解的作用是使DAO方法具有事务性。

我们使用JPA的API来处理数据库事务,因此我们将使用依赖注入来实例化EntityManager。

为了实现这一点,我们创建了带有@PersistenceContext注解的EntityManager属性。

实现 UserDetailsService

Spring提供了UserDetailsService来验证和授权用户。它从我们的DAO接收用户相关的数据。

MyAppUserDetailsService.java

package com.concretepage.config;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IUserInfoDAO;
import com.concretepage.entity.UserInfo;
@Service
public class MyAppUserDetailsService implements UserDetailsService {
	@Autowired
	private IUserInfoDAO userInfoDAO;
	@Override
	public UserDetails loadUserByUsername(String userName)
			throws UsernameNotFoundException {
		UserInfo activeUserInfo = userInfoDAO.getActiveUser(userName);
		GrantedAuthority authority = new SimpleGrantedAuthority(activeUserInfo.getRole());
		UserDetails userDetails = (UserDetails)new User(activeUserInfo.getUserName(),
				activeUserInfo.getPassword(), Arrays.asList(authority));
		return userDetails;
	}
}
实现 BasicAuthenticationEntryPoint

在我们的例子中,我们使用的是基于header的认证。

当我们不使用基于登录页面的认证时,对于任何对应用程序的请求,Spring需要发送一个带有适当状态代码的错误。

Spring提供了BasicAuthenticationEntryPoint,需要实现它来实现。

它有一个方法commence(),我们将覆盖该方法并返回一个状态代码(401),未授权的状态代码包含认证所需的认证类型的头。

在我们的例子中,我们使用的是基本认证。

AppAuthenticationEntryPoint.java

package com.concretepage.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class AppAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response,
		     AuthenticationException authException) throws IOException, ServletException {
		response.addHeader("WWW-Authenticate", "Basic realm="" + getRealmName() + """);
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		setRealmName("MY APP REALM");
	}
} 
Security 配置

现在我们将创建安全配置文件。

SecurityConfig.java

package com.concretepage.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private MyAppUserDetailsService myAppUserDetailsService;	
	@Autowired
	private AppAuthenticationEntryPoint appAuthenticationEntryPoint;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable()
		    .authorizeRequests()
		    .antMatchers("/user/**").hasAnyRole("ADMIN","USER")
		    .and().httpBasic().realmName("MY APP REALM")
		    .authenticationEntryPoint(appAuthenticationEntryPoint);
	} 
        @Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    	        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
                auth.userDetailsService(myAppUserDetailsService).passwordEncoder(passwordEncoder);
	}
} 

该类已被注解为@EnableWebSecurity,它从WebSecurityConfigurer类中配置了spring security。

如果我们想覆盖WebSecurityConfigurer的任何方法,那么我们要扩展WebSecurityConfigurerAdapter。

在我们的例子中,为了配置HttpSecurity,我们已经覆盖了configure()方法。

在这里,我们已经授权了一个带有/user/**模式的网址。

我们还将在这里配置BasicAuthenticationEntryPoint的实现类。

现在,autowire方法configureGlobal()中,我们用BCryptPasswordEncoder编码方案配置了UserDetailsService的实现类。

为了保护服务方法,我们需要使用@EnableGlobalMethodSecurity注解。

要使用@Secured注解启用方法级别的安全,配置securedEnabled元数据,数值为true。

要启用@PreAuthorize和@PostAuthorize注解,请将prePostEnabled元数据配置为true。

创建 DAO 用于 CRUD 操作

使用JPA EntityManager用于CRUD操作的DAO类。

IArticleDAO.java

package com.concretepage.dao;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleDAO {
    List
getAllArticles(); Article getArticleById(int articleId); void addArticle(Article article); void updateArticle(Article article); void deleteArticle(int articleId); boolean articleExists(String title, String category); }

ArticleDAO.java

package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.Article;
@Transactional
@Repository
public class ArticleDAO implements IArticleDAO {
	@PersistenceContext	
	private EntityManager entityManager;	
	@Override
	public Article getArticleById(int articleId) {
		return entityManager.find(Article.class, articleId);
	}
	@SuppressWarnings("unchecked")
	@Override
	public List
getAllArticles() { String hql = "FROM Article as atcl ORDER BY atcl.articleId"; return (List
) entityManager.createQuery(hql).getResultList(); } @Override public void addArticle(Article article) { entityManager.persist(article); } @Override public void updateArticle(Article article) { Article artcl = getArticleById(article.getArticleId()); artcl.setTitle(article.getTitle()); artcl.setCategory(article.getCategory()); entityManager.flush(); } @Override public void deleteArticle(int articleId) { entityManager.remove(getArticleById(articleId)); } @Override public boolean articleExists(String title, String category) { String hql = "FROM Article as atcl WHERe atcl.title = ? and atcl.category = ?"; int count = entityManager.createQuery(hql).setParameter(1, title) .setParameter(2, category).getResultList().size(); return count > 0 ? true : false; } }
创建带安全验证 CURD 操作的 Service

现在,我们将为CRUD操作创建具有安全验证的服务方法。

IArticleService.java

package com.concretepage.service;
import java.util.List;
import org.springframework.security.access.annotation.Secured;
import com.concretepage.entity.Article;
public interface IArticleService {
     @Secured ({"ROLE_ADMIN", "ROLE_USER"})
     List
getAllArticles(); @Secured ({"ROLE_ADMIN", "ROLE_USER"}) Article getArticleById(int articleId); @Secured ({"ROLE_ADMIN"}) boolean addArticle(Article article); @Secured ({"ROLE_ADMIN"}) void updateArticle(Article article); @Secured ({"ROLE_ADMIN"}) void deleteArticle(int articleId); }

角色为ADMIN的用户可以访问所有的方法。角色为USER的用户只能访问getAllArticle()和getArticleById()服务方法。

现在找到实现类。

ArticleService.java

package com.concretepage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IArticleDAO;
import com.concretepage.entity.Article;
@Service
public class ArticleService implements IArticleService {
	@Autowired
	private IArticleDAO articleDAO;
	@Override
	public Article getArticleById(int articleId) {
		Article obj = articleDAO.getArticleById(articleId);
		return obj;
	}	
	@Override
	public List
getAllArticles(){ return articleDAO.getAllArticles(); } @Override public synchronized boolean addArticle(Article article){ if (articleDAO.articleExists(article.getTitle(), article.getCategory())) { return false; } else { articleDAO.addArticle(article); return true; } } @Override public void updateArticle(Article article) { articleDAO.updateArticle(article); } @Override public void deleteArticle(int articleId) { articleDAO.deleteArticle(articleId); } }
创建 Controller 用于 CURD 操作

找到拥有CREATE、READ、UPDATE和DELETE(CRUD)操作方法的控制器类。

ArticleController.java

package com.concretepage.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;
@Controller
@RequestMapping("user")
public class ArticleController {
	@Autowired
	private IArticleService articleService;
	@GetMapping("article/{id}")
	public ResponseEntity
getArticleById(@PathVariable("id") Integer id) { Article article = articleService.getArticleById(id); return new ResponseEntity
(article, HttpStatus.OK); } @GetMapping("articles") public ResponseEntity> getAllArticles() { List
list = articleService.getAllArticles(); return new ResponseEntity>(list, HttpStatus.OK); } @PostMapping("article") public ResponseEntity addArticle(@RequestBody Article article, UriComponentsBuilder builder) { boolean flag = articleService.addArticle(article); if (flag == false) { return new ResponseEntity(HttpStatus.CONFLICT); } HttpHeaders headers = new HttpHeaders(); headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri()); return new ResponseEntity(headers, HttpStatus.CREATED); } @PutMapping("article") public ResponseEntity
updateArticle(@RequestBody Article article) { articleService.updateArticle(article); return new ResponseEntity
(article, HttpStatus.OK); } @DeleteMapping("article/{id}") public ResponseEntity deleteArticle(@PathVariable("id") Integer id) { articleService.deleteArticle(id); return new ResponseEntity(HttpStatus.NO_CONTENT); } }

从spring 4.3开始,我们有了请求映射注解,如
@GetMapping :HTTP GET方法
@PostMapping : HTTP POST方法
@PutMapping :HTTP PUT方法
@DeleteMapping :HTTP DELETE方法

我们为CRUD操作创建了以下网址。

1. Create :
方法: POST, 网址: /user/article

2. Read :
方法: GET, 网址: /user/article/{id}
方法: GET, 网址: /user/articles

3. Update :
方法: PUT, 网址: /user/article

4. Delete :
方法: DELETE, 网址: /user/article/{id}

使用 SpringApplication 创建主类

创建一个带有main()方法的类,它将调用SpringApplication.run()来运行应用程序。

首先下载所有的JAR依赖项,然后编译项目,然后启动嵌入式tomcat服务器。

MyApplication.java

package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {  
	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
        }       
} 

我们需要用@SpringBootApplication注解来注解这个类,它相当于@Configuration、@EnableAutoConfiguration和@ComponentScan注解。

使用 RestTemplate 创建客户端

为了消费REST网络服务,我们使用RestTemplate。对于认证,我们将在HttpHeaders中传递base64编码的凭证,作为username:password令牌,并进行基本授权。

RestClientUtil.java

package com.concretepage.client;
import java.net.URI;
import org.apache.tomcat.util.codec.binary.base64;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.concretepage.entity.Article;
public class RestClientUtil {
    private HttpHeaders getHeaders() {
    	String credential="mukesh:m123";
    	//String credential="tarun:t123";
    	String encodedCredential = new String(base64.encodebase64(credential.getBytes()));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
     	headers.add("Authorization", "Basic " + encodedCredential);
    	return headers;
    }
    public void getArticleByIdDemo() {
    	HttpHeaders headers = getHeaders();  
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/user/article/{id}";
        HttpEntity requestEntity = new HttpEntity(headers);
        ResponseEntity
responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article.class, 1); Article article = responseEntity.getBody(); System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle() +", Category:"+article.getCategory()); } public void getAllArticlesDemo() { HttpHeaders headers = getHeaders(); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/articles"; HttpEntity requestEntity = new HttpEntity(headers); ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class); Article[] articles = responseEntity.getBody(); for(Article article : articles) { System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle() +", Category: "+article.getCategory()); } } public void addArticleDemo() { HttpHeaders headers = getHeaders(); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article"; Article objArticle = new Article(); objArticle.setTitle("Spring REST Security using Hibernate"); objArticle.setCategory("Spring"); HttpEntity
requestEntity = new HttpEntity
(objArticle, headers); URI uri = restTemplate.postForLocation(url, requestEntity); System.out.println(uri.getPath()); } public void updateArticleDemo() { HttpHeaders headers = getHeaders(); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article"; Article objArticle = new Article(); objArticle.setArticleId(1); objArticle.setTitle("Update:Java Concurrency"); objArticle.setCategory("Java"); HttpEntity
requestEntity = new HttpEntity
(objArticle, headers); restTemplate.put(url, requestEntity); } public void deleteArticleDemo() { HttpHeaders headers = getHeaders(); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article/{id}"; HttpEntity
requestEntity = new HttpEntity
(headers); restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Void.class, 4); } public static void main(String args[]) { RestClientUtil util = new RestClientUtil(); //util.getArticleByIdDemo(); util.getAllArticlesDemo(); //util.addArticleDemo(); util.updateArticleDemo(); //util.deleteArticleDemo(); } }

在这里,我们正在执行创建、读取、更新和删除(CRUD)操作。我们可以使用具有ADMIN角色的mukesh/m123和具有USER角色的tarun/t123凭证来测试该应用程序。

运行应用程序

要运行该应用程序,首先在MySQL中创建表,如例子中给出的。现在我们可以通过以下方式运行REST网络服务。

1. 使用Eclipse

使用页面末尾的下载链接下载项目的源代码。

将该项目导入eclipse。

使用命令提示符,进入项目的根文件夹并运行。

mvn clean eclipse:eclipse 

然后在eclipse中刷新该项目。点击Run as -> Java Application来运行主类MyApplication。

Tomcat服务器将被启动。

2. 使用Maven命令

下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。

mvn spring-boot:run 

Tomcat服务器将被启动。

3. 使用可执行的JAR

使用命令提示符,转到项目的根文件夹并运行该命令。

mvn clean package 

我们将在目标文件夹中得到可执行的spring-boot-demo-0.0.1-SNAPSHOT.jar。以下列方式运行这个JAR。

java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar 

Tomcat服务器将被启动。

现在我们已经准备好测试这个应用程序了。要运行客户端,在eclipse中进入RestClientUtil类,点击Run as -> Java Application。

我们也可以使用Postman测试应用程序。

如图所示。

参考文献

【1】Spring Boot Security Features
【2】Spring Boot REST + JPA + Hibernate + MySQL Example
【3】Spring Boot Security REST + JPA + Hibernate + MySQL CRUD Example

源码下载

提取码:mao4
spring-boot-security-rest-jpa-hibernate-mysql-crud-example.zip

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/324592.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号