다음 환경에서 하나의 응용 프로그램을 실행하고 있습니다.
- GlassFish Server 4.0
- JSF 2.2.8-02
- PrimeFaces 5.1 파이널
- PrimeFaces Extension 2.1.0
- OmniFaces 1.8.1
- JPA 2.1을 사용하는 EclipseLink 2.5.2
- MySQL 5.6.11
- JDK-7u11
데이터베이스에서 느리게로드되는 여러 공개 페이지가 있습니다. 카테고리/하위 카테고리 별 추천, 인기 판매자, 새로운 도착 등의 제품 표시와 같은 몇 가지 CSS 메뉴가 템플릿 페이지의 헤더에 표시됩니다.
CSS 메뉴는 데이터베이스의 다양한 제품 카테고리에 따라 데이터베이스에서 동적으로 채워집니다.
이 메뉴는 페이지가로드 될 때마다 채워 지므로 완전히 필요하지 않습니다. 이러한 메뉴 중 일부는 복잡하고 비싼 JPA 기준 쿼리가 필요합니다.
현재 이러한 메뉴를 채우는 JSF 관리 Bean은보기 범위가 있습니다. 이들은 모두 응용 프로그램 범위를 지정하고 응용 프로그램 시작시 한 번만로드해야하며 해당 데이터베이스 테이블 (범주/하위 범주/제품 등)의 내용이 업데이트/변경 될 때만 업데이트해야합니다.
저는 이 및 this . 그들은 GlassFish 4.0에서 잘 작동했지만 데이터베이스는 포함하지 않았습니다. 여전히 WebSoket이 작동하는 방식을 제대로 이해할 수 없습니다. 특히 데이터베이스가 관련된 경우
이 시나리오에서는 해당 데이터베이스 테이블에 무언가가 업데이트/삭제/추가 될 때 관련 클라이언트에 알리고 위에서 언급 한 CSS 메뉴를 데이터베이스의 최신 값으로 업데이트하는 방법은 무엇입니까?
간단한 예가 좋을 것입니다.
- 답변 # 1
- 답변 # 2
Primefaces 및 Java EE 7을 사용하므로 구현하기 쉬워야합니다.
프라임 페이스 푸시 사용 (예 : http://www.primefaces.org/showcase/push/notify.xhtml)
Websocket 엔드 포인트를 수신하는보기 작성
데이터베이스 변경시 CDI 이벤트를 생성하는 데이터베이스 리스너 작성
이벤트의 페이로드는 최신 데이터의 델타이거나 정보를 업데이트 할 수 있습니다
Websocket을 통해 CDI 이벤트를 모든 클라이언트에게 전파
데이터를 업데이트하는 클라이언트
이것이 도움이되기를 바랍니다 더 자세한 내용이 필요하면
안녕
- 답변 # 3
PrimeFaces에는 구성 요소를 자동으로 업데이트하는 폴링 기능이 있습니다. 다음 예에서
와이즈 비즈<f:websocket>
<o:socket>
에 의해 3 초마다 자동 업데이트됩니다 .<h:outputText>
와 같은 리스너 메소드 작성 메뉴 데이터를 선택하십시오. 와이즈 비즈 메뉴 구성 요소가 자동으로 업데이트됩니다.<p:poll>
How to notify the associated clients and update the above-mentioned CSS menus with the latest values from the database?
process()
관련 자료
- pandas - matplot 및 python을 사용하여 데이터베이스에서 히스토그램 플로팅
- Neo4j-Spark 커넥터를 사용하는 동안 데이터베이스 이름 지정
- java - 여러 조각에서 Room 데이터베이스 사용
- C #을 사용하여 phpmyadmin mysql 데이터베이스에 연결하는 방법 (MysqlDataMysqlClient;사용)
- c# - 데이터베이스에서 ASPnet 웹 디스플레이 콘텐츠를 사용하여 루프 진행
- reactjs - Reactjs의 데이터베이스에서 가져온 이미지 경로를 사용하여 이미지를 표시하는 방법
- 장고 모델을 사용하여 데이터베이스에 Enter 키워드를 사용하여 문자 필드를 한 줄씩 저장하는 방법은 무엇입니까?
- java - Firebase 데이터베이스는 하나의 데이터 만 업데이트합니다
- PHP를 사용하여 mysql 데이터베이스 데이터를 javascript 함수에 전달하는 방법은 무엇입니까?
- python - PyMySQL을 사용하는 InterfaceError (데이터베이스 연결이 닫힘)
- sql - 파이썬을 사용하여 psql 데이터베이스에 테이블을 만드는 방법은 무엇입니까?
- Azure DevOps에서 PowerShell을 사용하여 SQLAzure에서 데이터베이스 이름 가져 오기
- postgresql - ubuntu204에서 pgadmin 4 v428을 사용하는 데이터베이스 가져 오기 오류
- Laravel의 원시 쿼리를 사용하여 SQL 데이터베이스에서 특정 열 가져 오기
- php - android url 연결 오류 - xampp를 사용하는 데이터베이스 연결 오류
- c# - Entity Framework 6을 사용하여 데이터베이스에서 업데이트되지 않는 엔티티
- java : Broken PrimeFaces 8.0.0 메시지 버블 수정
- javascript - Primefaces 마법사 탭에서 Enter 키 다운을 제어하는 방법은 무엇입니까?
- jsf - 페이지에 오류 메시지 - 트리 테이블 javaxfacesfacesexception : 트리 테이블의 값이 null이어야합니다
- jsf - p - 타임 라인 변경 이벤트 동작 지연
- jsf - Primefaces는 정렬 된 열의 이름을 얻습니다
- performance - h - commandbutton f : ajax 다른 형식의 실행 트리거 식
- jsf - 프라임 페이스 캘린더에서 이상하게 동작하는 경우
- jsf - autoComplete에서 화살표 아래로 키를 사용하여 completeMethod를 호출하는 방법은 무엇입니까?
- css - 데이터 테이블 열 필터 (달력)의 너비를 변경하는 방법은 무엇입니까?
- 부울에 대한 jsf 또는 primefaces 구성 요소/p - tristatecheckbox에 부울 사용 방법
서문
이 답변에서는 다음을 가정합니다.
<p:push>
사용에 관심이 없습니다. (중간에 정확한 이유를 남겨두고, 적어도 새로운 Java EE 7/JSR356 WebSocket API 사용에 관심이 있습니다)애플리케이션 범위 푸시를 원합니다 (즉, 모든 사용자가 한 번에 동일한 푸시 메시지를 수신하므로 세션에 관심이 없거나 범위 푸시를 보지 않음)
(MySQL) DB 측에서 직접 푸시를 호출하려고합니다 (따라서 엔티티 리스너를 사용하여 JPA 측에서 푸시를 호출하는 데 관심이 없습니다).수정: 어쨌든 두 단계를 모두 다룰 것입니다. 3a 단계는 DB 트리거를 설명하고 3b 단계는 JPA 트리거를 설명합니다. 둘 다 사용하거나 둘 다 사용하지 마십시오!
<시간>
1. WebSocket 엔드 포인트 생성먼저
@ServerEndpoint
를 만드십시오 기본적으로 모든 웹 소켓 세션을 응용 프로그램 전체 세트로 수집합니다. 이 특정 예에서는static
만 될 수 있습니다. 모든 웹 소켓 세션은 기본적으로 자체@ServerEndpoint
를 얻으므로 예를 들어 서블릿과 달리 상태 비 저장입니다.위의 예제에는 추가 메소드
sendAll()
가 있습니다 주어진 메시지를 열려있는 모든 웹 소켓 세션 (예 : 응용 프로그램 범위 푸시)으로 보냅니다. 이 메시지는 JSON 문자열 일 수도 있습니다.애플리케이션 범위 (또는 (HTTP) 세션 범위)에 명시 적으로 저장하려는 경우
ServletAwareConfig
를 사용할 수 있습니다. 이에 대한이 답변의 예입니다. 알다시피,ServletContext
속성이ExternalContext#getApplicationMap()
에 매핑 JSF (및HttpSession
) 속성이ExternalContext#getSessionMap()
에 매핑 ).
2. 클라이언트 측에서 WebSocket을 열고 들으십시오이 자바 스크립트를 사용하여 웹 소켓을 열고 들어보세요 :
현재로서는 푸시 된 텍스트 만 기록합니다. 이 텍스트를 메뉴 구성 요소를 업데이트하기위한 지침으로 사용하고 싶습니다. 이를 위해서는 추가
<p:remoteCommand>
가 필요합니다. .Push.sendAll("updateMenu")
에 의해 JS 함수 이름을 텍스트로 전송한다고 상상해보십시오 그러면 다음과 같이 해석하고 트리거 할 수 있습니다.$.parseJSON(event.data)
로 구문 분석 할 수 있음) ), 더 많은 역학이 가능합니다.
3a.DB 쪽에서 WebSocket 푸시를 트리거이제
Push.sendAll("updateMenu")
명령을 실행해야합니다. DB 쪽에서. DB가 웹 서비스에서 HTTP 요청을 시작하도록하는 가장 간단한 방법 중 하나입니다. 평범한 바닐라 서블릿은 웹 서비스처럼 행동하기에 충분합니다.필요한 경우 요청 매개 변수 또는 경로 정보를 기반으로 푸시 메시지를 매개 변수화 할 수 있습니다. 호출자가이 서블릿을 호출하도록 허용 된 경우 보안 점검을 수행하는 것을 잊지 마십시오. 그렇지 않으면 DB 이외의 다른 세계의 다른 사람이이를 호출 할 수 있습니다. 발신자의 IP 주소를 확인할 수 있습니다. 예를 들어 DB 서버와 웹 서버가 모두 같은 컴퓨터에서 실행되는 경우에 편리합니다.
DB가 해당 서블릿에서 HTTP 요청을 시작하게하려면 재사용 가능한 저장 프로 시저를 작성해야합니다.이 저장 프로시 저는 기본적으로 운영 체제 별 명령을 호출하여 HTTP GET 요청을 실행합니다 (예 : 와이즈 비즈 . MySQL은 기본적으로 OS 특정 명령 실행을 지원하지 않으므로 먼저 사용자 정의 함수 (UDF)를 설치해야합니다. mysqludf.org에서 SYS가 관심을 갖고있는 많은 것을 찾을 수 있습니다. 그것은curl
를 포함 우리가 필요로하는 기능. 설치가 완료되면 MySQL에서 다음 저장 프로 시저를 만듭니다.이제 삽입/업데이트/삭제 트리거를 생성하여이를 호출 할 수 있습니다 (테이블 이름이
DELIMITER // CREATE PROCEDURE menu_push() BEGIN SET @result = sys_exec('curl http://example.com/contextname/push-update-menu'); END // DELIMITER ;
라고 가정). ) :
3b.또는JPA 측에서 WebSocket 푸시를 트리거합니다요구 사항/상황이 JPA 엔터티 변경 이벤트 만 수신 할 수 있고 따라서 DB에 대한 외부 변경 사항이없을경우 적용 할 필요가없는 경우대신>3a 단계에서 설명한대로 DB 트리거는 JPA 엔티티 변경 리스너 만 사용합니다.
CREATE TRIGGER after_menu_delete AFTER DELETE ON menu FOR EACH ROW CALL menu_push();
를 통해 등록 할 수 있습니다@EntityListeners
에 주석 수업 :모든 프로젝트 (EJB/JPA/JSF)가 동일한 프로젝트에 함께 포함 된 단일 웹 프로파일 프로젝트를 사용하는 경우
그러나 "엔터프라이즈"프로젝트에서 서비스 계층 코드 (EJB/JPA/etc)는 일반적으로 EJB 프로젝트에서 분리되는 반면 웹 계층 코드 (JSF/Servlets/WebSocket/etc)는 웹 프로젝트에 유지됩니다. EJB 프로젝트는 웹 프로젝트에 대한 단일 종속성이 없어야합니다. 이 경우 CDI@Entity @EntityListeners(MenuChangeListener.class) public class Menu { // ... }
를 직접 호출 할 수 있습니다. 거기에.public class MenuChangeListener { @PostPersist @PostUpdate @PostRemove public void onChange(Menu menu) { Push.sendAll("updateMenu"); } }
를 해고하는 것이 좋습니다. 대신 웹 프로젝트가Event
할 수있는 .(결과에 주목;CDI
public class MenuChangeListener { // Outcommented because it's broken in current GF/WF versions. // @Inject // private Event<MenuChangeEvent> event; @Inject private BeanManager beanManager; @PostPersist @PostUpdate @PostRemove public void onChange(Menu menu) { // Outcommented because it's broken in current GF/WF versions. // event.fire(new MenuChangeEvent(menu)); beanManager.fireEvent(new MenuChangeEvent(menu)); } }
주입 현재 버전 (4.1/8.2)에서는 GlassFish와 WildFly에서 모두 손상되었습니다. 해결 방법은Event
를 통해 이벤트를 시작합니다. 대신;그래도 문제가 해결되지 않으면 CDI 1.1 대안은BeanManager
입니다. )그런 다음 웹 프로젝트에서 :
<시간>업데이트: 2016 년 4 월 1 일 (상기 답변 후 1 년 반) OmniFaces는 2.3 버전
@ApplicationScoped public class Application { public void onMenuChange(@Observes MenuChangeEvent event) { Push.sendAll("updateMenu"); } }
를 도입했습니다. 이 모든 것을 덜 회로 화해야합니다. 다가오는 JSF 2.3 Wyzwyz 주로<o:socket>
를 기반으로합니다. . JSF로 작성된 HTML 페이지에 서버가 비동기 변경 사항을 푸시하는 방법도 참조하십시오.