使用React,Spring Boot和用户身份验证构建CRUD应用程序

建筑物身份管理,包括身份验证和授权? 尝试Stormpath! 我们的REST API和强大的Java SDK支持可以消除您的安全风险,并且可以在几分钟内实现。 注册 ,再也不会建立auth了!

React是用于创建Web应用程序前端的最受欢迎的库之一。 使用Spring Boot 为面向React的应用程序创建CRUD后端比以往任何时候都更加容易。 在本教程中,我们将它们捆绑在一起,然后使用Stormpath添加身份验证和授权协议。

我们将从使用React创建一个静态数据视图开始。 然后,我们将使用Spring Boot创建一个REST后端,进行绑定,并使用Stormpath添加用户安全性。 即使您以前从未使用过React,一切也应该简单明了。

支持这篇文章的源代码可以在这个GitHub repo中找到。

服务前线

通常,React应用程序是使用Node.js来提供服务的,但是如果您是Java开发人员,则可能会对这种Spring Boot方法感到非常满意。

最初,您将整个应用程序放在一个文件index.html 。 要告诉Spring Boot将其用作主页,可以使用@Controller批注。

@Controller
public class HomeController {
 
    @RequestMapping(value = "/")
    public String index() {
        return "index.html";
    }
}

创建一个空目录,并将上面的代码放入src/main/java/tutorial/HomeController.java 。 然后,当您加载站点时,Spring Boot将寻找src/main/resources/static/index.html

<!DOCTYPE html>
<html>
<head>
    <title>React + Spring</title>
</head>
<body>
</body>
</html>

创建一个pom.xml和一个Spring Boot应用程序类。 将以下内容用于您的POM。

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.1.RELEASE</version>
    </parent>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

将以下内容放入src/main/java/tutorial/Application.java

@SpringBootApplication
public class Application {
 
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

当使用mvn spring-boot:run启动服务器并访问localhost:8080您应该看到一个空白页,标题为“ React + Spring”。

5563044

删除重启

通常,每次更改前端时都必须重新启动服务器,这很麻烦。 使用Spring Boot的开发人员工具可以使我们解决这个问题。 将以下依赖项添加到您的POM。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

还要将此配置添加到您的Spring Boot Maven插件中:

<configuration>
    <addResources>true</addResources>
</configuration>

现在,当您更改应用程序或重新编译任何类时,刷新浏览器时它应该会更新。

反应准系统HTML

开始反应! 最基本的React页面包含三件事:根元素,JavaScript导入和脚本标签。

<!DOCTYPE html>
<html>
<head>
    <title>React + Spring</title>
</head>
<body>
    <div id='root'></div>
 
    <script src="https://fb.me/react-15.0.1.js"></script>
    <script src="https://fb.me/react-dom-15.0.1.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
 
    <script type="text/babel"></script>
</body>
</html>

根元素是React将在其中插入视图HTML的位置。 导入引入了三个库-两个用于React本身,另一个用于使用babel翻译我们的视图模板。

注意:为了便于测试,我们使用CDN引入库,但是通常您会使用webpack之类的东西将所有Javascript合并到一个文件中。

现在,将您的React代码放入script标签中。

React基础

反应教程中的想法所述,您应该通过将接口分解为components来开始对应用程序进行编码。

<script type="text/babel">
var Employee = React.createClass({});
var EmployeeTable = React.createClass({});
</script>

在这里,您创建了两个-一个用于雇员表,另一个用于雇员条目。 然后,每个组件都需要一个渲染函数,该函数描述要生成HTML。

<script type="text/babel">
var Employee = React.createClass({
  render: function() {
    return (<div>employee</div>);
  }
});
var EmployeeTable = React.createClass({
  render: function() {
    return (<div>employee table</div>);
  }
});
</script>

这是Babel编译器用来将HTML代码转换为正确的React语句的地方。 注意div标签如何从render语句返回。

您需要告诉React将父组件HTML插入根元素。 这是使用ReactDOM.render方法完成的。

<script type="text/babel">
var Employee = React.createClass({
  render: function() {
    return (<div>employee</div>);
  }
});
var EmployeeTable = React.createClass({
  render: function() {
    return (<div>employee table</div>);
  }
});
 
ReactDOM.render(
  <EmployeeTable />, document.getElementById('root')
);
</script>

通过刷新浏览器,您应该看到您创建的简单文本元素。

26089170

要查看插入到根元素中HTML React,可以使用浏览器的检查器(Chrome中的Ctrl-Shift-J)。

22301758

将组件捆绑在一起

现在您已经有了组件,让我们将它们绑在一起。 您可以从尝试呈现硬编码的数据开始。 您稍后将使用REST服务器。

ReactDOM命令上方,输入以下内容:

var EMPLOYEES = [
  {name: 'Joe Biden', age: 45, years: 5},
  {name: 'President Obama', age: 54, years: 8},
  {name: 'Crystal Mac', age: 34, years: 12},
  {name: 'James Henry', age: 33, years: 2}
];

然后在实例化表时添加employees={EMPLOYEES}

ReactDOM.render(
  <EmployeeTable employees={EMPLOYEES} />, document.getElementById('root')
);

如您所料,这会将数据传递到名为employees的变量中。 在EmployeeTable内部,您可以使用this.props进行访问。 让我们用它来为每个雇员生成一个带有一行的表。

var EmployeeTable = React.createClass({
  render: function() {
    var rows = [];
    this.props.employees.forEach(function(employee) {
      rows.push(<Employee employee={employee} />);
    });
    return (
      <table>
        <thead>
          <tr>
            <th>Name</th><th>Age</th><th>Years</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>);
  }
});

这将为数据中的每个元素实例化一个新的Employee类(设置employee属性)并将其推入数组。 然后{rows}从子类中放入所需HTML。

现在,您需要做的就是更新Employee上的render方法。

var Employee = React.createClass({
  render: function() {
    return (
      <tr>
        <td>{this.props.employee.name}</td>
        <td>{this.props.employee.age}</td>
        <td>{this.props.employee.years}</td>
      </tr>);
  }
});

您可以添加Bootstrap以使表看起来不错。 在脚本导入标签的下方添加以下内容:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

然后用容器div包围主表,并为表元素提供一些Bootstrap类名称。

<div className="container">
  <table className="table table-striped">
    <thead>
      <tr>
        <th>Name</th>
        <th>Age</th>
        <th>Years</th>
      </tr>
    </thead>
    <tbody>{rows}</tbody>
  </table>
</div>

刷新浏览器应该可以很好地查看您硬编码的数据!

86263098

添加真实数据

要使用来自服务器的数据对象,您需要添加服务器! 使用Spring Boot做到这一点非常简单。 在src/main/java/tutorial/Employee.java添加以下代码:

@Data
@Entity
public class Employee {
 
    private @Id @GeneratedValue Long id;
    private String name;
    private int age;
    private int years;
 
    private Employee() {}
 
    public Employee(String name, int age, int years) {
        this.name = name;
        this.age = age;
        this.years = years;
    }
}

这是我们的豆。 注意: @Data批注来自Project Lombok

现在,使用Spring Data JPA创建一个存储库。

public interface EmployeeRepository extends CrudRepository<Employee, Long> {}

要加载数据,请创建一个CommandLineRunner实现,该实现使用存储库在数据库中创建新记录。

@Component
public class DatabaseLoader implements CommandLineRunner {
 
    private final EmployeeRepository repository;
 
    @Autowired
    public DatabaseLoader(EmployeeRepository repository) {
        this.repository = repository;
    }
 
    @Override
    public void run(String... strings) throws Exception {
        this.repository.save(new Employee("Joe Biden", 45, 5));
        this.repository.save(new Employee("President Obama", 54, 8));
        this.repository.save(new Employee("Crystal Mac", 34, 12));
        this.repository.save(new Employee("James Henry", 33, 2));
    }
}

剩下的唯一事情就是引入依赖关系。 将以下内容添加到pom.xml将使您的存储库成为REST端点。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

您还需要包括Project Lombok (可让您忽略为bean创建getter和setter)。

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
    <scope>provided</scope>
</dependency>

并且您需要一个数据库(Spring Boot会自动配置该数据库)。 您可以使用H2,它是嵌入式的(即在内存中/不会重新启动)。

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

就是这样! 如果现在重新启动,您将拥有一个具有数据功能的REST服务器。

映射URL

如果将以下内容添加到src/main/resources/application.properties则所有REST端点调用都将位于localhost:8080/api

spring.data.rest.basePath=/api

从命令行调用localhost:8080/api/employees应该会给出您加载的数据的列表。

反应和REST

现在,您需要将数据从REST端点拉入React视图。 您可以使用jQuery完成此操作。 将以下导入添加到HTML:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

现在创建一个包装器类,该包装器类在其render方法中返回EmployeeTable

var App = React.createClass({
 
  loadEmployeesFromServer: function () {
    var self = this;
    $.ajax({
      url: "http://localhost:8080/api/employees"
    }).then(function (data) {
      self.setState({employees: data._embedded.employees});
    });
  },
 
  getInitialState: function () {
    return {employees: []};
  },
 
  componentDidMount: function () {
    this.loadEmployeesFromServer();
  },
 
  render() {
    return ( <EmployeeTable employees={this.state.employees}/> );
  }
});

您必须首先使用getInitialState进行初始化来设置state ,然后使用componentDidMount来完成加载所有内容时所需的操作。

现在,将主ReactDOM.render替换为新类。

ReactDOM.render(<App />, document.getElementById('root') );

刷新后,您应该会看到与以前相同的视图,只是现在正在从服务器加载数据。

互动性

您需要为前端做的最后一件事是交互性。 让我们添加一个delete按钮,看看它如何工作。

将以下列添加到您的员工渲染中。

<td>
    <button className="btn btn-info" onClick={this.handleDelete}>Delete</button>
</td>

您将在handleDelete秒钟内编写handleDelete方法。 在雇员表类中添加另一个标题后,您应该看到每个条目旁边都出现了按钮。

8223957

从服务器删除

在将删除请求发送到后端之前,最好添加通知消息。 为此,您可以使用Toastr ,这将允许您显示弹出窗口。 在HTML顶部添加以下内容:

<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.css">

现在,您可以在脚本中使用toastr.error('something went wrong')类的命令发送消息。

让我们测试一下! 将您的员工类别更改为以下内容:

var Employee = React.createClass({
  getInitialState: function() {
    return {display: true };
  },
  handleDelete() {
    var self = this;
    $.ajax({
      url: self.props.employee._links.self.href,
      type: 'DELETE',
      success: function(result) {
        self.setState({display: false});
      },
      error: function(xhr, ajaxOptions, thrownError) {
        toastr.error(xhr.responseJSON.message);
      }
    });
  },
  render: function() {
    if (this.state.display==false) return null;
    else return (
      <tr>
        <td>{this.props.employee.name}</td>
        <td>{this.props.employee.age}</td>
        <td>{this.props.employee.years}</td>
        <td>
          <button className="btn btn-info" onClick={this.handleDelete}>Delete</button>
        </td>
      </tr>
    );
  }
});

这将设置一个display状态,该状态决定是否渲染。 如果成功删除了员工,则此变量设置为true。 handleDelete方法将删除请求发送到服务器(使用从get请求返回的href)。 如果成功,则将display设置为false并更新渲染。 否则,Toastr会通知用户发生错误。

尝试删除条目并刷新页面。 它应该保持删除状态。

注意:由于您正在使用内存数据库,因此重新启动服务器将恢复相同的数据。

添加用户身份验证

让我们在React应用程序中添加一项最终功能,即Stormpath,以进行用户身份验证。 您将需要使用Stormpath永久免费的开发人员帐户

您需要做的第一件事是将Stormpath应用程序详细信息放在application.properties

stormpath.application.href = <your app href>
stormpath.client.apiKey.id = <your api key id>
stormpath.client.apiKey.secret = <your api key secret>

注意:出于安全原因,您不应将Stormpath密钥存储在项目文件中。 而是使用环境变量。 这里

接下来,将Stormpath启动器添加到您的Maven依赖项中。

<dependency>
    <groupId>com.stormpath.spring</groupId>
    <artifactId>stormpath-default-spring-boot-starter</artifactId>
    <version>1.1.2</version>
</dependency>

您还需要将index.html文件移动到src/main/resources/templates这是因为Stormpath的Spring Boot启动程序默认使用Thymeleaf模板库。 更改HomeController以也返回index

@Controller
public class HomeController {
 
    @RequestMapping(value = "/")
    public String index() {
        return "index";
    }
}

您还需要将您的React代码移动到一个单独的文件中。 这是因为Thymeleaf不喜欢某些角色。 将代码从脚本标签的内部移至src/main/webapp/public/app.js 默认情况下,此文件夹对公众开放。 然后将此脚本导入HTML的底部。

<script type="text/babel" src="/public/app.js"></script>

然后创建一个安全适配器,调用该适配器适用于stormpath()

@Configuration
public class Security extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.apply(stormpath());
    }
}

现在,当您重新启动服务器并尝试访问主页时,将出现登录页面提示。

3503857

输入您在application.properties放入的Stormpath应用程序附带的详细信息,应像以前一样将您带到数据视图页面。

注销

您还需要能够注销。 这就像添加一个将帖子发送到/logout的表单一样简单(Stormpath会默认设置该表单)。

<div class='container'>
    <div id='root'></div>
    <form action="/logout" method="post">
        <input class="btn btn-danger center-block" type="submit" value="Logout" />
    </form>
</div>

您可以用Bootstrap容器包围React根元素和表单,以更好地对齐。

3245088

单击注销按钮将使您返回到以前的登录屏幕。

设置授权

最后,您只想让具有正确访问权限的用户删除员工。 要锁定内容,可以使用Spring Security的PreAuthorize注释。 将存储库代码更改为以下内容:

public interface EmployeeRepository extends CrudRepository<Employee, Long> {
 
    @PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @Override
    void delete(Long aLong);
}

现在,只有具有ROLE_ADMIN权限的用户才能删除。 如果重新启动服务器并尝试单击“删除”,则应收到一条消息,提示“访问被拒绝”。

36408723

要为用户提供所需的权限,您需要通过管理控制台将其添加到Stormpath组中。

73134913-1024x423

在此示例中,有一个名为Supervisor的组已附加到相关应用程序。 要与该组集成,只需将ROLE_ADMIN字符串替换为该组的HREF并重新启动。 如果登录的用户是Supervisor组的成员(请参阅帐户),则应允许您删除。

尘埃落定

就像您已经创建了一个以授权和React为前端的兼容CRUD Web应用程序。 希望本教程对您有所帮助! 如果您对集成React,Spring Boot和Stormpath有任何疑问,请发表评论。

要查看使用Spring Boot后端的更完整的React应用程序,请参阅React.js和Spring Data REST

建筑物身份管理,包括身份验证和授权? 尝试Stormpath! 我们的REST API和强大的Java SDK支持可以消除您的安全风险,并且可以在几分钟内实现。 注册 ,再也不会建立auth了!

翻译自: https://www.javacodegeeks.com/2016/12/build-crud-application-react-spring-boot-user-authentication.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值