使用Java 8,Spring Boot和Angular创建简单的Web应用程序

2,687 阅读6分钟

入门条件

· Java 8已安装。

· 任何Java IDE(最好是STS或IntelliJ IDEA)。

· 使用HTML,CSS和JavaScript,基本了解基于Java和Spring的Web开发和UI开发。

背景

在本文中,我将尝试使用Java 8和Spring Boot创建一个小型端到端Web应用程序。

我选择了SpringBoot,因为它更容易配置并且可以很好地与其他技术堆栈配合使用。我还使用了REST API和SpringData JPA以及H2数据库。

我使用 Spring Initializer 添加所有依赖项,并使用我的所有配置创建一个空白的工作项目。

我使用Maven作为构建工具,但也可以使用Gradle。

pom.xml

<?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>

    <groupId>com.example</groupId>

    <artifactId>bootdemo</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>

    <name>bootDemo</name>

    <description>Demo project for Spring Boot</description>

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.5.3.RELEASE</version>

        <relativePath />

        <!-- lookup parent from repository
-->

    </parent>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <java.version>1.8</java.version>

    </properties>

    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-jpa</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-devtools</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-rest</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>

            <groupId>com.h2database</groupId>

            <artifactId>h2</artifactId>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

        <dependency>

            <groupId>org.springframework.restdocs</groupId>

            <artifactId>spring-restdocs-mockmvc</artifactId>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>

        </plugins>

    </build>

</project>
 

在UI部分,我使用了AngularJS和BootStrap CSS以及基本的JS,CSS和HTML。

这是一个非常简单的可用于创建Web应用程序的项目,。

结构



实施

让我们从SpringBootApplication类开始。

@SpringBootApplication

public class BootDemoApplication {

 @Autowired

 UserRepository userRepository;

 public static void main(String[] args) {

 
SpringApplication.run(BootDemoApplication.class, args);

 }

}

我们现在创建Controller。

@Controller

public class HomeController {

 @RequestMapping("/home")

 public String home() {

  return "index";

 }

}

这将作为我们SPA的主页。现在我们创建一个Controller来处理一些REST调用。

@RequestMapping("/user")

@RestController

public class UserController {

 @Autowired

 UserService
userService;

 @RequestMapping(Constants.GET_USER_BY_ID)

 public UserDto getUserById(@PathVariable Integer userId) {

  return userService.getUserById(userId);

 }

 @RequestMapping(Constants.GET_ALL_USERS)

 public List < UserDto > getAllUsers() {

  return userService.getAllUsers();

 }

 @RequestMapping(value = Constants.SAVE_USER, method =
RequestMethod.POST)

 public void saveUser(@RequestBody UserDto userDto) {

 
userService.saveUser(userDto);

 }

}

在这里,我们有不同的方法来处理来自客户端的不同测试调用。

我在Controller中安装了一个Service类 UserService

public interface UserService {

 UserDto
getUserById(Integer userId);

 void saveUser(UserDto userDto);

 List < UserDto
> getAllUsers();

}

@Service

public class UserServiceimpl implements
UserService {

 @Autowired

 UserRepository
userRepository;

 @Override

 public UserDto getUserById(Integer userId) {

  return
UserConverter.entityToDto(userRepository.getOne(userId));

 }

 @Override

 public void saveUser(UserDto userDto) {

 
userRepository.save(UserConverter.dtoToEntity(userDto));

 }

 @Override

 public List < UserDto > getAllUsers() {

  return
userRepository.findAll().stream().map(UserConverter::entityToDto).collect(Collectors.toList());

 }

}

在典型的Web应用程序中,通常有两种类型的数据对象:DTO(通过客户端进行通信)和实体(通过DB进行通信)。

DTO

public class UserDto {

    Integer userId;

    String userName;

   
List<SkillDto> skillDtos= new ArrayList<>();

    public UserDto(Integer userId, String userName, List<SkillDto> skillDtos) {

        this.userId = userId;

        this.userName = userName;

        this.skillDtos = skillDtos;

    }

    public UserDto() {

    }

    public Integer getUserId() {

        return userId;

    }

    public void setUserId(Integer userId) {

        this.userId = userId;

    }

    public String getUserName() {

        return userName;

    }

    public void setUserName(String userName) {

        this.userName = userName;

    }

    public List<SkillDto> getSkillDtos() {

        return skillDtos;

    }

    public void setSkillDtos(List<SkillDto> skillDtos) {

        this.skillDtos = skillDtos;

    }

}

public class SkillDto {

    Integer skillId;

    String SkillName;

    public SkillDto(Integer skillId, String skillName) {

        this.skillId = skillId;

        SkillName =
skillName;

    }

    public SkillDto() {

    }

    public Integer getSkillId() {

        return skillId;

    }

    public void setSkillId(Integer skillId) {

        this.skillId = skillId;

    }

    public String getSkillName() {

        return SkillName;

    }

    public void setSkillName(String skillName) {

        SkillName =
skillName;

    }

}

Entity

@Entity

public class User implements Serializable{

    private static final long serialVersionUID = 0x62A6DA99AABDA8A8L;

@Column

@GeneratedValue(strategy = GenerationType.AUTO)

@Id

private Integer userId;

    @Column

    private String userName;

    @OneToMany(cascade = CascadeType.ALL, fetch =
FetchType.EAGER)

    private List<Skill> skills= new LinkedList<>();

    public Integer getUserId() {

        return userId;

    }

    public void setUserId(Integer userId) {

        this.userId = userId;

    }

    public String getUserName() {

        return userName;

    }

    public void setUserName(String userName) {

        this.userName = userName;

    }

    public List<Skill> getSkills() {

        return skills;

    }

    public void setSkills(List<Skill> skills) {

        this.skills = skills;

    }

    public User() {

    }

    public User(String userName, List<Skill> skills) {

        this.userName = userName;

        this.skills = skills;

    }

}

@Entity

public class Skill {

    @Column

@GeneratedValue(strategy = GenerationType.AUTO)

@Id

private Integer skillId;

    @Column

    private String skillName;

    @ManyToOne

    private User user;

    public Skill(String skillName) {

this.skillName = skillName;

}

public Integer getSkillId() {

        return skillId;

    }

    public void setSkillId(Integer skillId) {

        this.skillId = skillId;

    }

    public String getSkillName() {

        return skillName;

    }

    public void setSkillName(String skillName) {

        this.skillName = skillName;

    }

    public User getUser() {

        return user;

    }

    public void setUser(User user) {

        this.user = user;

    }

    public Skill() {

    }

    public Skill(String skillName, User user) {

        this.skillName = skillName;

        this.user = user;

    }

}

对于数据库操作,我们使用SpringData JPA:

@Repository

public interface UserRepository extends
JpaRepository<User, Integer>{

}

@Repository

public interface SkillRepository extends
JpaRepository<Skill, Integer>{

}

在默认情况下,扩展JpaRepository 提供了大量的CRUD操作,也可以使用它来创建自己的查询方法。

为了转换DTO - >Entity和Entity - > DTO,我创建了一些基本的转换器类。

public class UserConverter {

 public static User dtoToEntity(UserDto userDto) {

  User user = new User(userDto.getUserName(), null);

 
user.setUserId(userDto.getUserId());

 
user.setSkills(userDto.getSkillDtos().stream().map(SkillConverter::dtoToEntity).collect(Collectors.toList()));

  return user;

 }

 public static UserDto entityToDto(User user) {

  UserDto userDto =
new UserDto(user.getUserId(),
user.getUserName(), null);

 
userDto.setSkillDtos(user.getSkills().stream().map(SkillConverter::entityToDto).collect(Collectors.toList()));

  return userDto;

 }

}

public class SkillConverter {

 public static Skill dtoToEntity(SkillDto SkillDto) {

  Skill Skill = new Skill(SkillDto.getSkillName(), null);

 
Skill.setSkillId(SkillDto.getSkillId());

  return Skill;

 }

 public static SkillDto entityToDto(Skill skill) {

  return new SkillDto(skill.getSkillId(), skill.getSkillName());

 }

}

现在让我们关注UI部分。

使用Angular时,我们需要遵循一些指导原则。

index.html

<!DOCTYPE html>

<html>

<head>

    <meta charset="ISO-8859-1">

    <title>Main Page</title>

</head>

<body ng-app="demo">

<hr/>

<div class="container" ng-controller="UserController">

    <div class="row">

        <label>User</label> <input type="text" ng-model="userDto.userName" class="input-sm
spacing"/>

        <label>Skills</label> <input type="text" ng-model="skills" ng-list class="input-sm custom-width spacing"

                                     placeholder="use comma to separate skills"/>

        <button ng-click="saveUser()" class="btn btn-sm
btn-info">Save User</button>

    </div>

    <hr/>

    <div class="row">

        <p>{{allUsers | json}}</p>

    </div>

    <hr/>

    <div class="row" ng-repeat="user in
allUsers">

        <div class="">

            <h3>{{user.userName}}</h3>

            <span ng-repeat="skill in
user.skillDtos" class="spacing">{{skill.skillName}}</span>

        </div>

    </div>

</div>

</body>

<script src="js/lib/angular.min.js"></script>

<script src="js/lib/ui-bootstrap-tpls-2.5.0.min.js"></script>

<script src="js/app/app.js"></script>

<script src="js/app/UserController.js"></script>

<script src="js/app/UserService.js"></script>

<link rel="stylesheet" href="css/lib/bootstrap.min.css"/>

<link rel="stylesheet" href="css/app/app.css"/>

</html>

在创建HTML时,不要忘记导入所需的JS和CSS文件。


app.js

'use strict'

var demoApp = angular.module('demo', ['ui.bootstrap', 'demo.controllers',

    'demo.services'

]);

demoApp.constant("CONSTANTS", {

    getUserByIdUrl:
"/user/getUser/",

    getAllUsers: "/user/getAllUsers",

    saveUser: "/user/saveUser"

});

UserController.js

'use strict'

var module = angular.module('demo.controllers', []);

module.controller("UserController", ["$scope", "UserService",

    function($scope, UserService) {

        $scope.userDto = {

            userId:
null,

           
userName: null,

           
skillDtos: []

        };

        $scope.skills = [];

        UserService.getUserById(1).then(function(value) {

           
console.log(value.data);

        }, function(reason) {

           
console.log("error
occured");

        }, function(value) {

           
console.log("no
callback");

        });

        $scope.saveUser = function() {

            $scope.userDto.skillDtos = $scope.skills.map(skill => {

                return {

                   
skillId: null,

                   
skillName: skill

                };

            });

            UserService.saveUser($scope.userDto).then(function() {

               
console.log("works");

                UserService.getAllUsers().then(function(value) {

                    $scope.allUsers = value.data;

                }, function(reason) {

                   
console.log("error
occured");

                }, function(value) {

                   
console.log("no
callback");

                });

                $scope.skills = [];

                $scope.userDto = {

                   
userId: null,

                   
userName: null,

                   
skillDtos: []

                };

            }, function(reason) {

               
console.log("error
occured");

            }, function(value) {

               
console.log("no
callback");

            });

        }

    }

]);

UserService.js

'use strict'

angular.module('demo.services', []).factory('UserService', ["$http", "CONSTANTS", function($http, CONSTANTS) {

    var service = {};

    service.getUserById = function(userId) {

        var url = CONSTANTS.getUserByIdUrl + userId;

        return $http.get(url);

    }

    service.getAllUsers = function() {

        return $http.get(CONSTANTS.getAllUsers);

    }

    service.saveUser = function(userDto) {

        return $http.post(CONSTANTS.saveUser, userDto);

    }

    return service;

}]);

app.css

body{

   
background-color: #efefef;

}

span.spacing{

    margin-right: 10px;

}

input.custom-width{

    width: 200px;

}

input.spacing{

    margin-right: 5px;

}

可以使用以下方法构建应用程序

mvn clean install 或者java -jar bootdemo-0.0.1-SNAPSHOT.jar

打开浏览器并点击 http:// localhost:8080 / home

在打开一个简单的页面之后,输入名称和技能,输入的数据将保留在数据库中。



本人创业团队产品MadPecker,主要做BUG管理、测试管理、应用分发,网址:www.madpecker.com,有需要的朋友欢迎试用、体验!
本文为MadPecker团队技术人员编写,转载请标明出处