从用户界面到数据库的Angular自动填充

一位开发人员展示了他为Angular和Spring Boot编写的大量代码,他用它创建了一个完整的堆栈Web应用程序。

该MovieManager项目用于管理我的电影的收集和使用角度和Spring启动PostgreSQL的做到这一点。

该项目用于演示如何为电影标题构建自动完成搜索框。自动完成框在前端使用Bootstrap 4,在后端使用PostgreSQL的Spring Boot。重点在于如何将本地Angular / RxJS与Spring Boot以及关系数据库一起使用。

从用户界面到数据库的Angular自动填充

前端

前端使用Angular与RxJS和Bootstrap 4进行造型。Angular和RxJS具有创建输入并将其连接到后端REST服务的功能。

然后,在每次击键之后,服务的结果将在输入下方的div中显示和更新。Bootstrap提供CSS类来设置组件的样式。

前端有三部分:

  1. 带输入标签和输出div的div模板。

  2. 具有表单控件的组件类,用于将输入标记与服务方法相连接。

  3. 向服务器发出REST请求的服务类。

在搜索组件中,我使用了以下 模板:

...

Searchfor Movie Title

Loading

...

第1-2行创建一个可变宽度和一行的Bootstrap容器。

第4行为自动填充功能创建引导列。

第5-8行创建一个输入组,它用一个标签显示样式化输入,并将Angular form控件链接movieTitle 到输入。

如果在输入中输入了某些内容,第9行将创建结果div。

如果服务从服务器检索电影,则第10行显示文本“加载”。

第11行显示了从服务器加载的电影的路由器链接。这 routerLink 是电影组件与电影ID的路由。 *ngFor 对服务器发送的电影进行迭代,并且 async 意味着电影是在到达时显示其数据的观察者。链接的文本是电影标题。

在搜索组件中,我使用了以下类:

@Component({

selector: 'app-search',

templateUrl: './search.component.html',

styleUrls: ['./search.component.scss']

})

export class SearchComponent implements OnInit {

generes: Genere[];

movieTitle = new FormControl();

movies: Observable;

movieActor = new FormControl();

actors: Observable;

importMovies: Movie[] = [];

importMovieTitle = new FormControl();

actorsLoading = false;

moviesLoading = false;

importMoviesLoading = false;

showMenu = false;

moviesByGenere: Movie[] = [];

moviesByGenLoading = false;

constructor(private actorService: ActorsService, private movieService: MoviesService, private userService: UsersService) { }

ngOnInit() {

this.actors = this.movieActor.valueChanges

.debounceTime(400)

.distinctUntilChanged()

.do(() => this.actorsLoading = true)

.switchMap(name => this.actorService.findActorByName(name))

.do(() => this.actorsLoading = false);

this.movies = this.movieTitle.valueChanges

.debounceTime(400)

.distinctUntilChanged()

.do(() => this.moviesLoading = true)

.switchMap(title => this.movieService.findMovieByTitle(title))

.do(() => this.moviesLoading = false);

this.userService.allGeneres().subscribe(res => this.generes = res);

}

第1-6行使用注释和OnInit 界面创建搜索组件。

第9行为movieTitle 用户输入创建 表单控件。

第16行创建 moviesLoading 布尔值来显示加载文本。

第31行将movieTitle 表单控件与 valueChanges observable和Observable结果链接起来movies。

第32-33行在请求到后端之间添加了400 ms的超时时间,并且只在输入发生更改时才发送请求。

第34行设置显示模板中加载文本的布尔值。

第35行用于 switchMap 丢弃正在运行的请求并向服务发送新的请求。

第36行设置将加载文本设置为false的布尔值。

这是管理所有电影数据的电影服务:

@Injectable()

export class MoviesService {

private _reqOptionsArgs = { headers: new HttpHeaders().set( 'Content-Type', 'application/json' ) };

constructor(private http: HttpClient) { }

...

public findMovieByTitle(title: string) :Observable {

if(!title) {

return Observable.of([]);

}

return this.http.get('/rest/movie/'+title, this._reqOptionsArgs).catch(error => {

console.error( JSON.stringify( error ) );

return Observable.throw( error );

});

}

...

}

第1-2行MoviesService 用注释创建。

第3行创建HTTP头。

第5行是获取注入的HttpClient的构造函数。

Observable 如果标题为空,则第10-12行将返回 空白。

第13-16行将HTTP请求发送到服务器,捕获服务器错误,记录它们并引发错误。

后端

后端在Spring Boot中使用JPA和PostgreSQL完成。它使用Spring Boot功能为REST界面和服务提供服务,以管理存储库并围绕服务调用创建事务。这些事务需要支持MovieManager中的电影功能的导入和删除。

存储库使用JPA创建一个查询,查找包含(区分大小写)用户输入的标题字符串的用户电影的电影标题。

REST服务是在这个类中创建的:

@RestController

@RequestMapping("rest/movie")

public class MovieController {

@Autowired

private MovieManagerService service;

...

@RequestMapping(value="/{title}", method=RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

public ResponseEntity> getMovieSearch(@PathVariable("title") String titleStr) throws InterruptedException {

List movies = this.service.findMovie(titleStr);

return new ResponseEntity>(movies, HttpStatus.OK);

}

...

}

第5-6行注入了MovieManagerService。它管理事务,并且是电影数据的公共服务。

第10-11行设置了RequestMapping并获得请求字符串的标题值。

第12行从这个标题字符串的MovieManagerService读取电影列表。

第13行将电影列表包装在ResponseEntity中并返回它。

主要的电影服务是在这个类中创建的:

@Transactional

@Service

public class MovieManagerService {

@Autowired

private CrudMovieRepository crudMovieRep;

@Autowired

private CrudCastRepository crudCastRep;

@Autowired

private CrudActorRepository crudActorRep;

@Autowired

private CrudGenereRepository crudGenereRep;

@Autowired

private CrudUserRepository crudUserRep;

@Autowired

private CustomRepository customRep;

@Autowired

private AppUserDetailsService auds;

...

public List findMovie(String title) {

List result = this.customRep.findByTitle(title).stream()

.map(m -> Converter.convert(m)).collect(Collectors.toList());

return result;

}

...

}

第14-15行获得 CustomRepository 注入。这是所有非CRUD DB请求的回购。

第23-24行将Movie Dtos中的Movie实体列表转换为可以由该序列化 RestController 并返回Dto列表。

自定义库在此创建类:

@Repository

public class CustomRepository {

@PersistenceContext

private EntityManager em;

@Autowired

private CrudUserRepository crudUserRep;

...

public List findByTitle(String title) {

User user = getCurrentUser();

List results = em.createQuery("select e from Movie e join e.users u where e.title like :title and u.id = :userid", Movie.class).setParameter("title", "%"+title+"%").setParameter("userid", user.getId()).getResultList();

return results;

}

...

}

第3-4行获得注入Jpa的EntitiyManager。

第5-6行获取注入的CrudUserRepository以访问当前登录的用户。多用户支持需要当前用户。

第12-13行向EntityManager查询电影标题包含标题字符串和当前用户是电影所有者的电影。为此,电影和用户实体需要被连接,然后通过电影标题和userId进行过滤。然后返回结果。

概要

Angular和RxJ具有在几行代码中创建自动完成的功能。诸如击键之间的超时,没有双重请求以及丢弃陈旧结果之类的功能由本地功能支持。链接到valueChanges observable 的表单控件 将更新div中的结果。

DZone有一篇很好的文章,描述了Angular及其一些功能。Java开发人员熟悉依赖注入,静态类型和注释等许多功能,并使Angular易于学习。这使得Angular成为对前端开发感兴趣的Java开发人员的非常好的框架。

后端是带有服务和JPA存储库的小型REST控制器。Spring Boot使得用几行代码和几个注释创建后端成为可能。


分享到:


相關文章: