Java EE 6示例– Galleria –第3部分

關于Galleria示例的先前文章( 第1 部分 | 第2部分 | 第3部分 | 第4部分 )指導您完成基礎知識以及對GlassFish和WebLogic的初始部署。 從今天開始,我嘗試在其中添加一些企業級功能,因為我發現他們在自己的項目中提出了很多要求。 我知道Vineet還將隨著時間的推移添加更多功能 ,我希望這不會對讀者造成混淆。 但是,讓我們看看這是如何實現的,以及我的哪些功能被Vineet所采用,而哪些不是:)。 讓我知道您是否想添加任何特別的東西!

會話固定

企業Java應用程序最熱門的話題是安全性。 由于它具有許多不同的方面,因此我決定從一個非常簡單但經常需要的功能入手:防止會話固定。 這不是Java或JSF特有的,而是基于Web的應用程序的普遍問題。 當會話ID易于發現或猜測時,就會出現會話固定。 攻擊的主要方法是URL或響應的任何其他部分中存在會話ID。 攻擊者可以捕獲一個會話,然后將鏈接嵌入到其頁面中,誘使用戶訪問該會話并成為其會話的一部分。 然后,當用戶認證時,會話即被認證。 在這里使用Cookies只能提供一定的安全性,因為大多數情況下還通過暗示保密性丟失的方法進行設置。 大多數應用服務器會根據第一個請求生成一個新的會話ID。 認證通過后,可以再次使用。 防止這種情況的唯一方法是在成功的身份驗證請求之后發出新的隨機會話。
一般來說,這很容易做到。 轉到galleria-jsf項目并找到info.galleria.view.user.Authenticator bean。 將以下行添加到authenticate()方法的開頭:

String result = null;
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();// Session Fixation Prevention
HttpSession session = (HttpSession) externalContext.getSession(false);if (logger.isDebugEnabled()) {logger.debug("Session before authentication request: " + session.getId());}session.invalidate();
session = (HttpSession) externalContext.getSession(true);if (logger.isDebugEnabled()) {logger.debug("Session after authentication request: " + session.getId());}

就是這樣 第一次接觸代碼庫就很容易進行更改。 切換到軟件包信息info.galleria的調試級別FINE應該在日志文件中揭示魔術:

[#|2012-03-27T17:17:25.298+0200|FINE|glassfish3.1.2|info.galleria.view.user.Authenticator|_ThreadID=27;
_ThreadName=Thread-4;ClassName=info.galleria.view.user.Authenticator;MethodName=
authenticate;|Session before authentication request: 33b1205d7ad740631978ed211bce|#][#|2012-03-27T17:17:25.301+0200|FINE|glassfish3.1.2|info.galleria.view.user.Authenticator
|_ThreadID=27
;_ThreadName=Thread-4;ClassName=info.galleria.view.user.Authenticator;MethodName
=authenticate;|Session after authentication request: 33b1f344ad1730c69bccc35e752e|#]

如預期的那樣,我們在身份驗證請求期間更改了http會話。 您也可以使用您選擇的瀏覽器插件(在本例中為“編輯此Cookie”)進行檢查:

通過執行此操作,Galleria應用程序變得更加安全。 如果您想了解有關會話固定的更多信息,請閱讀OWASP頁面 。

防止多次登錄

下一個要求要復雜一些。 我已經看過幾次了,即使對用戶來說不方便,出于安全原因也可能是必需的。 正如您可能已經猜到的,沒有一個單獨的開關。 您必須持有會話圖,并檢查用戶是否已經登錄。 在登錄過程中應進行檢查,并顯示有意義的錯誤消息。

其中有一些棘手的部分。 第一個是,您需要一種方法來存儲應用程序的所有用戶和HttpSession信息。 第二個是,您需要一個人來照顧它。 讓我們從最新開始。

您在這里需要著名的辛格爾頓。 一個地方來存儲相關的HttpSession信息。 首先想到的是使用.getExternalContext()。getApplicationMap()。 這可能有效。 我們在此處設置的登錄限制有一些副作用。 想象一下,一個用戶沒有登錄就登錄并崩潰了他/她的瀏覽器。 他/她最終將無法重新登錄,直到進行一些清理或重新啟動應用程序為止。 因此,在HttpSessionListener中訪問它也至關重要。 鑒于事實,即JSF ExternalContext是ServletContext,我們在這里很安全。

在繼續進行有關聚類的更多討論之前。 我們將在這里構建一個非集群構造。 根據Servlet規范,上下文屬性對于創建它們的JVM是本地的。 因此,如果您在集群環境中運行此命令,將會失去保護,因為您可以在集群的每個節點上進行會話。 使該群集安全將意味著使用數據庫,ejb組件或分布式緩存。

轉到info.galleria.view.util并創建一個名為SessionConcierge的新最終類。 它需要添加和刪除會話的方法。 我們顯然需要一些東西來處理應用程序映射。 從addSession方法開始,稍后將從info.galleria.view.user.Authenticator托管Bean中調用該方法:

public static boolean addSession(HttpSession session) {String account = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();String sessionId = session.getId();if (account != null && !getApplicationMap(session).containsKey(account)) {getApplicationMap(session).put(account, sessionId);if (logger.isDebugEnabled()) {logger.debug("Added Session with ID {} for user {}", sessionId, account);}return true;} else {logger.error("Cannot add sessionId, because current logged in account is NULL or session already assigned!");return false;}}

基本上,這將檢查我們是否在這里有登錄用戶,以及該用戶是否已經分配了會話。 如果有一個用戶并且他沒有正在使用的會話,我們將把當前會話添加到該帳戶下的應用程序映射中作為鍵。 接下來一點刪除邏輯:

public static void removeSession(HttpSession session) {String sessionId = session.getId();String account = getKeyByValue(getApplicationMap(session), sessionId);if (account != null) {getApplicationMap(session).remove(account);if (logger.isDebugEnabled()) {logger.debug("Removed Session with ID {} for user {}", sessionId, account);}}}

這有點棘手。 您注意到,我使用該帳戶作為在地圖中綁定會話的密鑰。 因此,我必須花一點點技巧來反轉地圖并通過值找到鍵。 這個小魔術在這里發生:

private static <T, E> T getKeyByValue(Map<T, E> map, E value) {for (Entry<T, E> entry : map.entrySet()) {if (value.equals(entry.getValue())) {return entry.getKey();}}return null;}

做完了 一件事失蹤。 getApplicationMap(HttpSession session)方法。 這不是很神奇。 它只是試圖弄清楚我們是否需要通過FacesContext或ServletContext獲取它。 如果您感到好奇,請查看SessionConcierge源。 最后要做的是將SessionConcierge添加到Authenticator中 。 將此代碼添加到try {request.login()}中(我為您的定位添加了前兩行:

request.login(userId, new String(password));result = "/private/HomePage.xhtml?faces-redirect=true";// save sessionId to disable multiple sessions per userif (!SessionConcierge.addSession(session)) {request.logout();logger.error("User {} allready logged in with another session", userId);FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, Messages.getString("Login.AllreadyLoggedIn", locale), null);FacesContext.getCurrentInstance().addMessage(null, facesMessage);}

如果通過SessionConcierge添加HttpSession失敗,則立即注銷用戶并添加FacesMessage。 請記住將其添加到galleria-jsf \ src \ main \ resources \ resources messages.properties及其翻譯中。 并且不要忘記添加

SessionConcierge.removeSession(session);

到公共String logout()。 精細。 就是這樣,不是嗎? 至少它現在正在工作。 但是我們仍然必須解決那些崩潰的瀏覽器問題。 如果某人未通過該應用程序注銷,會話超時或瀏覽器崩潰,則在重新啟動該應用程序之前,您將無法再次登錄。 那是不可思議的。 需要某種清理機制。 HttpSessionListener呢? 聽起來不錯! 將其添加到info.galleria.listeners中,并將其命名為SessionExpirationListener 。

@Overridepublic void sessionDestroyed(HttpSessionEvent se) {HttpSession session = se.getSession();SessionConcierge.removeSession(session);if (logger.isDebugEnabled()) {logger.debug("Session with ID {} destroyed", session.getId());}}

精細。 現在應該可以了。 繼續嘗試一下。 打開兩個不同的瀏覽器,然后嘗試同時登錄。 只有一個可以讓您訪問該應用程序。 第二個應該以您放入messages.properties中的錯誤消息作為響應。 請注意,這不是多窗口預防措施。 您仍然可以根據需要自由地為每個HttpSession打開盡可能多的窗口。

一個小的補充:如果您嚴重依賴HttpSessionListener清理,則應確保它具有正確的生存期。 通過產品特定的Web應用程序部署描述符(例如weblogic.xml或glassfish-web.xml)進行配置。 我建議將其設置為合理的較低值(例如30分鐘或更短),以免用戶等待太長時間。 這是Glassfish(glassfish-web.xml)的外觀:

<session-config><session-properties><property name="timeoutSeconds" value="1800" /></session-properties></session-config>

和用于WebLogic(weblogic.xml)

<session-descriptor><timeout-secs>180</timeout-secs></session-descriptor>

Galleria Java EE 6示例應用程序正在增長。 今天,我將寫關于如何優雅地處理錯誤的文章。 關于用戶輸入驗證,已經做了很多工作,但是仍然有很多失敗情況沒有得到解決,應該解決。 如果您對過去發生的事情感到好奇,請查看本系列的第一部分: 基礎知識 , 在GlassFish上 運行,在WebLogic 上 運行 , 測試和增強安全性 。

通用異常機制

應用程序使用檢查的異常在層之間傳遞錯誤。 ApplicationException是所有可能的業務異常的根源。

這些業務異常在域和表示層之間傳達驗證沖突和所有已知錯誤。 galleria-jsf視圖項目中的<domain> Manager(例如AlbumManger)類將其捕獲,并使用ExceptionPrecessor將錯誤消息填充到視圖中。 在這兩層之間可能發生的另一種異常是RuntimeExceptions。 那些被容器包裝到EJBException中,并且還被<domain> Manager類捕獲。 這些會生成更一般的錯誤消息,并顯示給用戶。

在這里,我不會涉及檢查與未檢查的異常(如果您好奇的話,Google會介紹一下 )。 當應用程序有機會從錯誤中恢復時,我傾向于使用檢查異常。 當某些事情無法恢復時,將引發未經檢查的檢查。 這就是原因,我對目前內置的異常處理機制不滿意。 我稍后再討論。

有什么不見了? ViewExpired等。

似乎現在一切都已處理。 但只有第一印象。 打開登錄屏幕,稍等片刻,讓您的http會話超時。 現在,您會看到一個不太漂亮的ViewExpired異常屏幕。

如果您以登錄用戶的身份嘗試登錄,則只需將其重定向到登錄頁面。 無論如何,對于表示層中的一些其他意外情況,可能會出現相同的錯誤頁面。 因此,讓我們修復此問題。 最明顯的事情是簡單地引入專用的錯誤頁面。

<error-page><exception-type>javax.faces.application.ViewExpiredException</exception-type><location>/viewExpired.xhtml</location></error-page>

現在,您將用戶重定向到專用頁面,該頁面可以告訴他/她有關工作場所安全性的一些知識,并且不會使應用長時間處于無人看管狀態。 這適用于大多數應用程序。 如果您愿意在頁面上獲得一些其他信息,或者只是想捕獲多個異常并單獨處理它們而不必靜態配置它們,則需要一種稱為ExceptionHandler的東西。 這是JSF 2中的新功能,您所需要做的就是實現ExceptionHandler,并且它是工廠。 工廠本身在facex-config.xml中配置,因為沒有任何注釋。

打開faces-config.xml,并在底部添加以下幾行:

<factory><exception-handler-factory>info.galleria.handlers.GalleriaExceptionHandlerFactory</exception-handler-factory></factory>

現在,我們將在專用包中實現GalleriaExceptionHandlerFactory 。 有趣的方法是:

@Overridepublic ExceptionHandler getExceptionHandler() {ExceptionHandler result = parent.getExceptionHandler();result = new GalleriaExceptionHandler(result);return result;}

每個請求調用一次,每次調用必須返回一個新的ExceptionHandler實例。 在這里,真正的ExceptionHandlerFactory被調用并被要求創建實例,然后將該實例包裝在自定義的GalleriaExceptionHandler類中。 這是真正有趣的事情發生的地方。

@Overridepublic void handle() throws FacesException {for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {ExceptionQueuedEvent event = i.next();ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();Throwable t = context.getException();if (t instanceof ViewExpiredException) {ViewExpiredException vee = (ViewExpiredException) t;FacesContext fc = FacesContext.getCurrentInstance();Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();NavigationHandler nav =fc.getApplication().getNavigationHandler();try {// Push some stuff to the request scope for later use in the pagerequestMap.put("currentViewId", vee.getViewId());nav.handleNavigation(fc, null, "viewExpired");fc.renderResponse();} finally {i.remove();}}}// Let the parent handle all the remaining queued exception events.getWrapped().handle();}

使用從getUnhandledExceptionQueuedEvents()。iterator()返回的迭代器迭代非處理程序異常。 ExeceptionQueuedEvent是一個SystemEvent,您可以從中獲取實際的ViewExpiredException。 最后,您從異常中提取了一些其他信息,并將其放在請求范圍內,以便稍后通過頁面中的EL進行訪問。 ViewExpiredException要做的最后一件事是使用JSF隱式導航系統(“ viewExpired”解析為“ viewExpired.xhtml”)并通過NavigationHandler導航至“ viewExpired”頁面。 不要忘記在finally塊中刪除已處理的異常。 您不希望父異常處理程序再次處理此問題。 現在,我們必須創建viewExpired.xhtml頁面。 在galleria-jsf \ src \ main \ webapp文件夾中執行此操作。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"template="./templates/defaultLayout.xhtml"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"><ui:define name="title"><h:outputText value="#{msg['Exception.page.title']}" /></ui:define><ui:define name="content"><h:form><h:outputText value="#{msg['Exception.page.message']}" /><p>You were on page #{currentViewId}.  Maybe that's useful.</p><p>Please re-login via the <h:outputLink styleClass="homepagelink" value="#{request.contextPath}/Index.xhtml" ><h:outputText value="Homepage" /></h:outputLink>.</p></h:form></ui:define>
</ui:composition>

請注意,我在此處添加了新的消息屬性,因此您需要確保將它們放在galleria-jsf \ src \ main \ resources \ resources \ messages.properties和翻譯中。

到目前為止,這顯然只處理一種特殊的異常實例。 您可以將其擴展為也可以處理其他內容。 現在我們已經有了基本的機制,您可以自由地執行此操作。

重構RuntimeException處理

如我所說,我對應用程序處理RuntimeExceptions的方式不滿意。 現在我們已經有了一個很好的中央異常處理,我們可以將這些內容稍微移動一下并重構* Manager類。 從所有它們中刪除所有這些catch(EJBException ejbEx){塊。 我們將在一分鐘內在GalleriaExceptionHandler中進行處理。 只需將另一個檢查添加到GalleriaExceptionHandler即可,如果引發了ViewExpiredException以外的任何其他異常,則將用戶重定向到另一個頁面。

// check for known Exceptionsif (t instanceof ViewExpiredException) {ViewExpiredException vee = (ViewExpiredException) t;// Push some stuff to the request scope for later use in the pagerequestMap.put("currentViewId", vee.getViewId());} else {forwardView = "generalError";Locale locale = fc.getViewRoot().getLocale();String key = "Excepetion.GeneralError";logger.error(Messages.getLoggerString(key), t);String message = Messages.getString(key, locale);FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null);fc.addMessage(null, facesMessage);}

這種方法具有一些優點。 它減少了* Manager類中所需的代碼,并且我們終于有了一個中心位置來處理那些不可恢復的異常。 這還是不是很像企業。 想象一下,您的第一級支持團隊需要照顧客戶,他們開始抱怨他們收到的唯一消息是“ GeneralError”。 那不是很有幫助。 您的支持團隊將需要升級它,第二或第三級需要檢查日志和and and ..所有這些都是由于我們已知的錯誤。 首先要做的是找出導致錯誤的原因。 解析堆棧跟蹤并不是很大的樂趣。 特別是不是包含在EJBExceptions中以及在FacesExceptions中的RuntimeExceptions中。 感謝上帝提供Apache Commons ExceptionUtils 。 打開您的galleria-jsf pom.xml并將其添加為依賴項:

<dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency>

現在,您可以開始檢查根本原因:

} else {forwardView = "generalError";// no known instance try to specifyThrowable causingEx = ExceptionUtils.getRootCause(t);if (causingEx == null) {causingEx = t;}
//...logger.error(Messages.getLoggerString(key), t);requestMap.put("errorCode", errorCode);

別忘了在這里也記錄完整的堆棧跟蹤(t,不僅是causeEx)。 通常,讓用戶知道異常是一件壞事。 沒有人真正希望看到錯誤發生(因為我們討厭犯錯誤),并且在所有異常之后,堆棧跟蹤都可以泄露您不希望在屏幕上某個地方看到的敏感信息。 因此,您需要找到一種方法來顯示對用戶有意義的內容,而又不會過多披露。 那就是著名的錯誤代碼起作用的地方。 使用根本原因異常作為消息鍵,或自行決定要為此付出的努力。 它可能是一個錯誤類別的系統(數據庫,接口系統等),它們為第一級支持提供了有關導致錯誤的原因的良好提示。 從一開始我就堅持一個簡單的解決方案。 只需為每個捕獲的異常生成一個UUID并將其跟蹤到日志和UI。 以下是一個非常簡單的示例。

String errorCode = String.valueOf(Math.abs(new Date().hashCode()));

這也應該添加到消息屬性中,并且不要忘記,您還需要另一個用于generalError模板。 如果slf4j將使用與jdk日志記錄相同的消息格式,那么您只需要一個屬性..

Exception.generalError.log=General Error logged: {}.
Exception.generalError.message=A general error with id {0} occured. Please call our hotline.

將此添加到generalError.xhtml并查看如何將錯誤代碼傳遞到消息模板。

<h:outputFormat  value="#{msg['Exception.generalError.message']}" ><f:param value="#{errorCode}"/></h:outputFormat>

這里還有很多需要改進的地方。 您可以使用javax.faces.application.ProjectStage查找應用程序正在運行的當前模式。如果您在ProjectStage.Development中運行,則還可以將完整的堆棧跟蹤信息放到UI上,并使調試工作變得容易一些。 以下代碼段嘗試從JNDI獲取ProjectStage。

public static boolean isProduction() {ProjectStage stage = ProjectStage.Development;String stageValue = null;try {InitialContext ctx = new InitialContext();stageValue = (String) ctx.lookup(ProjectStage.PROJECT_STAGE_JNDI_NAME);stage = ProjectStage.valueOf(stageValue);} catch (NamingException | IllegalArgumentException | NullPointerException e) {logger.error("Could not lookup JNDI object with name 'javax.faces.PROJECT_STAGE'. Using default 'production'");}return ProjectStage.Production == stage;}

那三位數的Http錯誤頁呢?

那是另一件事。 其余所有3位http錯誤代碼,這些錯誤代碼將返回看起來不太好看的錯誤頁面之一。 唯一要做的就是將它們映射到web.xml中,如下所示:

<error-page><error-code>404</error-code><location>/404.xhtml</location></error-page>

您應該確保已放置這些映射,并向用戶顯示有意義的錯誤。 始終提供一種從那里進一步導航的方法應該成為最佳實踐。

參考: Java EE 6示例–使用Galleria增強安全性–第5部分 , Java EE 6示例–優雅地處理Galleria中的錯誤–我們JCG合作伙伴 Markus Eisele在Java企業軟件開發博客上的第6部分 。


翻譯自: https://www.javacodegeeks.com/2012/04/java-ee-6-example-galleria-part-3.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372876.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372876.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372876.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在 Windows 上測試 Redis Cluster的集群填坑筆記

redis 集群實現的原理請參考http://www.tuicool.com/articles/VvIZje集群環境至少需要3個節點。推薦使用6個節點配置&#xff0c;即3個主節點&#xff0c;3個從節點。新建6個文件夾 分別是 7000/7001/7002/7003/7004/7005將redis.windows.conf 復制一份然后修改配置文件中的下面…

不成為編程天才的5種貢獻方式

安迪萊斯特&#xff08;Andy Lester&#xff09;早在三月發布了原始指南&#xff0c;其中介紹了14種不成為編程天才或搖滾明星的貢獻開源的方法 &#xff0c;我真的很喜歡這個想法。 這就是為什么我決定稍微采納一下這篇文章&#xff0c;并告訴您如何以及可以做什么來支持自己喜…

mysql數據庫設計與應用答案智慧樹_智慧樹_MySQL數據庫設計與應用_完整免費答案...

單位工程施工組織設計的技術經濟指標體系包括有()。A&#xff0e;工期指標B&#xff0e;勞動指標C&#xff0e;臺班利用率D&#xff0e;成本降低大跨徑橋梁采用()將會取得良好的技術經濟效益。A&#xff0e;橫移法施工B&#xff0e;頂推法施工C&#xff0e;轉體法施工D&#xf…

拓撲排序最長鏈-P3119 [USACO15JAN]草鑒定Grass Cownoisseur

https://www.luogu.org/problem/show?pid3119 本來我是來練習tarjan的&#xff0c;結果tarjan部分直接copy了&#xff0c;反而拓撲排序部分想了好久&#xff1b; 這道題SZB大神兩次就AC&#xff1b; 但我等到AC&#xff0c;寫好題解就只能洗洗睡了&#xff1b; 唉~ 差距怎…

談談父類和子類的隔離性

以前寫代碼知道要給類外設置訪問接口, 例如下例: 1 class Money2 {3 public:4 Money(int money) : m_curValue(money){}5 6 void store(int money) { m_curValue money;}7 void spent(int money){ m_curValue - money;}8 private:9 int m_curValue…

用于數據庫測試的DBUnit,Spring和注釋

如果您曾經嘗試用Java編寫數據庫測試&#xff0c;則可能會碰到DBUnit 。 DBUnit允許您設置和拆除數據庫&#xff0c;以便它包含可針對其編寫測試的一致行。 通常&#xff0c;您可以通過編寫一個簡單的XML文檔來指定要DBUnit插入的行&#xff0c;例如&#xff1a; <?xml ve…

阿里云centos 7.6安裝mysql_阿里云Centos7上安裝MySQL教程

1 基本安裝過程1.查看系統是否安裝了mysql軟件# rpm -qa|grep -i mysql2.將已經安裝過的軟件卸載掉。注意&#xff1a;這樣的卸載是不徹底&#xff0c;不過這里夠用了# yum remove 軟件名3.CentOS 7的yum源中默認是沒有mysql的。所以&#xff0c;為了解決這個問題我們首先下載安…

Struts2中數據封裝方式

一、通過ActionContext類獲取 public class ActionContextDemo extends ActionSupport { Override public String execute() throws Exception { //獲取ActionContext對象 ActionContext context ActionContext.getContext(); //調用getParameters…

第五章、搭建S3C6410開發板的測試環境

通過對本章的學習&#xff0c;我對s3c6410開發板的測試環境有了一定的認識&#xff0c;并掌握了如下的知識點&#xff1a;一、對于s3c6410這款開發板&#xff0c;它是一款低功耗、高性價比的處理器&#xff0c;它是基于ARM11的內核。二、不同開發板的區別主要在燒錄嵌入式系統的…

IBM JVM調整– gencon GC策略

本文將向您詳細介紹從Java虛擬機&#xff08;例如HotSpot或JRockit&#xff09;遷移到IBM JVM時重要的Java堆空間調整注意事項。 該調整建議基于我為我的一個IT客戶端執行的最新故障排除和調整任務。 IBM JVM概述 正如您可能從其他文章中看到的那樣&#xff0c;IBM JVM在某些方…

mysql主從配置錯誤_mysql主從配置失敗,主從通訊失敗

配置mysql主從的時候&#xff0c;檢查slave狀態&#xff0c;發現報錯信息&#xff0c;Error The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement on query.mysql> show slave status\G*************************** 1. r…

echarts如何顯示在頁面上

echarts如何顯示在頁面上 1.引入echarts的相關.js文件 <script src"js/echarts.min.js"></script> 2.新建一個div&#xff0c;style自己定&#xff0c;但必須要有width和height <div id"history_state" style"width: 400px;height: 20…

懶惰的JSF Primefaces數據表分頁–第2部分

頁面代碼非常簡單&#xff0c;沒有復雜性。 檢查“ index.xhtml”代碼&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www…

二分匹配之最大權值匹配算法---KM模板

百科&#xff1a;http://baike.baidu.com/link?urlvbM3H4XmfrsWfP-epdlR2sVKSNzOq4hXnWDqm5uo8fd7VWsF2SmhDV35XyVUDvVjvrtf42RUITJuNCHn-7_x6K 大神總結&#xff1a;http://www.cnblogs.com/skyming/archive/2012/02/18/2356919.html 代碼&#xff1a; 1 #include<stdio.h…

java實現報表_用存儲過程和 JAVA 寫報表數據源有什么弊端?

用存儲過程和 JAVA 寫報表數據源有什么弊端&#xff1f;跟著小編一起來一看一下吧&#xff01;我們在報表開發中經常會使用存儲過程準備數據&#xff0c;存儲過程支持分步計算&#xff0c;可以實現非常復雜的計算邏輯&#xff0c;為報表開發帶來便利。所以&#xff0c;報表開發…

SpringMVC學習筆記整理

SpringMVC學習筆記 以下是我整理的SpringMVC學習筆記&#xff1a; 導入jar包 一&#xff1a;springmvc工作流程。 ①. servlet容器初始化一個request請求 ②. DispatcherServlet分發器負責發送請求到映射器. ③. despatcherServlet把請求交給處理器映射Mapping&…

Java EE重新審視設計模式:異步

盡管您可能找不到作為設計模式列出的異步方法調用&#xff0c;但我還是值得一提。 因此&#xff0c;這是我的JavaEE Revisits設計模式系列的最后一篇文章。 異步方法調用只不過是多線程。 基本上&#xff0c;它是指將在單獨的線程中運行的方法調用&#xff0c;因此主&#xff0…

am335x watchdog

am335x watchdog 內核文檔kernel/Documentation/watchdog Qtaplex:~/kernel/7109/linux-3.2.0/Documentation/watchdog$ ll total 88 drwxrwxr-x 3 Qt Qt 4096 Jun 8 15:11 ./ drwxrwxr-x 94 Qt Qt 12288 Apr 28 13:09 ../ -rwxrwxr-x 1 Qt Qt 576 Nov 20 2013 00-INDEX -rwxrw…

springboot2 使用hikaridatasource 并測試_基于Spring Boot 2.x的后端管理網站腳手,源碼免費分享...

基于Spring Boot 2.x 的 Material Design 的后端管理網站腳手架 &#xff1a;提供權限認證 用戶管理 菜單管理 操作日志 等常用功能去繁就簡 重新出發基于Spring Boot 集成一些常用的功能&#xff0c;你只需要基于它做些簡單的修改即可。功能列表&#xff1a;權限認證權限管理用…

測試驅動開發–雙贏策略

敏捷從業人員談論測試驅動開發 &#xff08;TDD&#xff09;&#xff0c;所以許多關心代碼質量和可操作性的開發人員也是如此。 我曾幾何時&#xff0c;不久前設法閱讀了有關TDD的文章。 據我了解&#xff0c;TDD的關鍵是&#xff1a; 編寫測試&#xff0c;但失敗 代碼&#x…