一位開發人員展示了他為Angular和Spring Boot編寫的大量代碼,他用它創建了一個完整的堆棧Web應用程序。
該MovieManager項目用於管理我的電影的收集和使用角度和Spring啟動PostgreSQL的做到這一點。
該項目用於演示如何為電影標題構建自動完成搜索框。自動完成框在前端使用Bootstrap 4,在後端使用PostgreSQL的Spring Boot。重點在於如何將本地Angular / RxJS與Spring Boot以及關係數據庫一起使用。
前端
前端使用Angular與RxJS和Bootstrap 4進行造型。Angular和RxJS具有創建輸入並將其連接到後端REST服務的功能。
然後,在每次擊鍵之後,服務的結果將在輸入下方的div中顯示和更新。Bootstrap提供CSS類來設置組件的樣式。
前端有三部分:
帶輸入標籤和輸出div的div模板。
具有表單控件的組件類,用於將輸入標記與服務方法相連接。
向服務器發出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使得用幾行代碼和幾個註釋創建後端成為可能。
閱讀更多 愛碼農 的文章