使用Spring Security保護GWT應用程序

在本教程中,我們將看到如何將GWT與Spring的安全模塊(即Spring Security)集成在一起。 我們將看到如何保護GWT入口點,如何檢索用戶的憑據以及如何記錄各種身份驗證事件。 此外,我們將實現自定義身份驗證提供程序,以便可以重用現有的身份驗證方案。

如果您是JavaCodeGeeks的普通讀者,那么現在您可能應該知道我們真的很喜歡GWT 。 過去,賈斯汀(Justin)在GWT上寫了一些殺手G的文章: 如何將GWT與Spring和Hibernate(JPA)集成以及如何在混合中添加Eclipse和Maven 。 此外,我已經寫了關于如何在GWT應用程序中添加JSON功能 , 如何為GWT添加CAPTCHA以及如何開始使用SmartGWT的文章 。 最后,Pat寫了有關構建自己的GWT Spring Maven原型并集成GWT,EJB3,Maven和JBoss的文章 。

因此,我們現在開始使用Spring的Security模塊就不足為奇了。 如官方站點所述, Spring Security是一個功能強大且高度可定制的身份驗證和訪問控制框架。 它是用于保護基于Spring的應用程序的實際標準 。 Spring Security是Acegi框架的演變,該框架在后臺使用Spring以便主要為Web應用程序提供安全性。 但是,Spring Security現在是一個完善的安全框架,它不僅包含針對Web的功能,而且還包含針對LDAP集成和ACL創建的功能。 在開始本教程之前,最好先閱讀一下Spring Security參考文檔并準備好Spring Security API Javadocs 。

在本教程中,我將使用GWT 2.1.0和Spring Security 3.0.5。 您可以在此處下載最新的生產版本。 您可能已經猜到了,還需要Spring核心框架中的一些庫。 您可以在此處下載框架。

讓我們開始在Eclipse中創建一個新的Web應用程序項目(我想您已經安裝了Eclipse的Google插件,并且已經部署了GWT)。 我為該項目的名稱選擇了深奧的名稱“ GwtSpringSecurityProject”。 Eclipse屏幕如下所示:

將Spring安全性添加到我們的項目的第一步是在“ web.xml”文件中聲明一個過濾器。 這個過濾器是FilterChainProxy類的實例,它將攔截所有傳入的請求,并將請求的控件委派給適當的Spring處理程序。 相關的Web聲明文件片段如下:

…
<filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
...

我們還必須在“ web.xml”中定義一個ContextLoaderListener以便引導Spring上下文。 這是通過以下代碼段完成的:

…<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
...

接下來,我們在“ war / WEB-INF”文件夾中創建一個名為“ applicationContext.xml”的文件。 在那里,我們聲明了Spring Security相關信息。 最重要的元素是“ http ”,它可以用來定義應在哪些URL上應用安全性,以及用戶應具有哪些角色才能訪問特定資源。 在我們的示例中,代碼段如下:

…
<http auto-config="true"><intercept-url pattern="/gwtspringsecurityproject/**" access="ROLE_USER"/><intercept-url pattern="/gwt/**" access="ROLE_USER"/><intercept-url pattern="/**/*.html" access="ROLE_USER"/><intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
</http>
...

簡而言之,上述內容要求角色“ ROLE_USER”才能訪問“ gwt”和“ gwtspringsecurityproject”文件夾(與GWT相關的資源所在)下的文件。 同樣,所有HTML文件(如GWT的入口點)都需要相同的角色。 “ IS_AUTHENTICATED_ANONYMOUSLY”意味著所有用戶都可以訪問特定資源,而不必成為特定角色的一部分。 通過簡單地使用“ http ”元素,Spring將使用默認的登錄頁面和注銷URL。

所有身份驗證請求均由AuthenticationManager處理,因此必須在文件中聲明其實例。 更具體地說,通常將請求委托給AuthenticationProvider 。 可以使用一些已經創建的實現,例如DaoAuthenticationProvider (與DB中定義的角色和用戶一起使用時)或LdapAuthenticationProvider (根據LDAP服務器對用戶進行身份驗證)。 但是,出于本教程的目的,我們將創建一個自定義身份驗證提供程序,并將其與spring的安全基礎結構集成。

在深入研究應用程序的代碼之前,我們必須首先處理依賴項。 這是必須添加到項目的類路徑中的JAR:

  • org.springframework.context-3.0.5.RELEASE.jar
  • Spring安全核心-3.0.5.RELEASE.jar
  • spring-security-web-3.0.5.RELEASE.jar

好的,現在我們準備好了。 我們的提供程序非常簡單,僅使用靜態Map來存儲用戶及其相應的密碼。 這是代碼:

package com.javacodegeeks.gwt.security.server.auth;import java.util.HashMap;
import java.util.Map;import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;public class CustomAuthenticationProvider implements AuthenticationProvider {private static Map<String, String> users = new HashMap<String, String>();static {users.put("fabrizio", "javacodegeeks");users.put("justin", "javacodegeeks");}@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {String username = (String) authentication.getPrincipal();String password = (String)authentication.getCredentials();if (users.get(username)==null)throw new UsernameNotFoundException("User not found");String storedPass = users.get(username);if (!storedPass.equals(password))throw new BadCredentialsException("Invalid password");Authentication customAuthentication = new CustomUserAuthentication("ROLE_USER", authentication);customAuthentication.setAuthenticated(true);return customAuthentication;}@Overridepublic boolean supports(Class<? extends Object> authentication) {return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);}}

讓我們從頭開始對該代碼進行詳細說明。 supports方法定義了此提供程序提供的身份驗證的類型。 在我們的例子中, UsernamePasswordAuthenticationToken是我們希望處理的那個。 該實現旨在簡化用戶名和密碼的顯示。

實現了authenticate方法,并在其中檢索登錄表單中提供的用戶名(通過getPrincipal方法)以及隨附的密碼(通過getCredentials方法)。 首先,我們檢查特定的用戶名是否存在,如果不存在,則拋出UsernameNotFoundException 。 同樣,如果用戶名存在但密碼不正確, 則會引發BadCredentialsException 。 請注意,這兩個異常都擴展了父AuthenticationException類。

如果用戶名和密碼均正確,我們將對用戶進行身份驗證。 為此,我們必須返回Authentication接口的具體實例。 在這種情況下,我們必須封裝已知的用戶信息(憑證等)以及用戶所具有的角色(權限)。 請注意,分配的角色(ROLE_USER)與“ applicationContext.xml”文件中聲明的角色匹配。 另外,必須調用setAuthenticated方法(以true作為參數),以向其余身份驗證鏈指示特定用戶已成功通過我們的模塊進行身份驗證。 讓我們看看在這種情況下如何定義自定義身份驗證對象:

package com.javacodegeeks.gwt.security.server.auth;import java.util.ArrayList;
import java.util.Collection;import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;public class CustomUserAuthentication implements Authentication {private static final long serialVersionUID = -3091441742758356129L;private boolean authenticated;private GrantedAuthority grantedAuthority;private Authentication authentication;public CustomUserAuthentication(String role, Authentication authentication) {this.grantedAuthority = new GrantedAuthorityImpl(role);this.authentication = authentication;}@Overridepublic Collection<GrantedAuthority> getAuthorities() {Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();authorities.add(grantedAuthority);return authorities;}@Overridepublic Object getCredentials() {return authentication.getCredentials();}@Overridepublic Object getDetails() {return authentication.getDetails();}@Overridepublic Object getPrincipal() {return authentication.getPrincipal();}@Overridepublic boolean isAuthenticated() {return authenticated;}@Overridepublic void setAuthenticated(boolean authenticated) throws IllegalArgumentException {this.authenticated = authenticated;}@Overridepublic String getName() {return this.getClass().getSimpleName();}}

在構造函數中,我們傳遞用戶的角色和原始的Authentication對象。 在已實現的方法中,最重要的一個是getAuthorities ,它返回已授予主體的權限。 該信息在GrantedAuthority對象的集合內提供。

現在讓我們看看“ applicationContext.xml”的樣子:

<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"><beans:bean id="customAuthListener" class="com.javacodegeeks.gwt.security.server.auth.CustomAuthListener"/><http auto-config="true"><intercept-url pattern="/gwtspringsecurityproject/**" access="ROLE_USER"/><intercept-url pattern="/gwt/**" access="ROLE_USER"/><intercept-url pattern="/**/*.html" access="ROLE_USER"/><intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" /></http><beans:bean id="customAuthenticationProvider" class="com.javacodegeeks.gwt.security.server.auth.CustomAuthenticationProvider" />    <authentication-manager alias="authenticationManager"><authentication-provider ref="customAuthenticationProvider"/></authentication-manager></beans:beans>

除“ CustomAuthListener”外,聲明文件的每個元素均已定義。 作為Spring框架的一部分,Spring Security允??許應用程序開發人員提供回調,這些回調將在應用程序生命周期的特定部分被調用。 因此,當發生特定的身份驗證事件時,我們可以注冊要調用的方法。 在我們的例子中,我們將創建一個偵聽器,該偵聽器接收AbstractAuthorizationEvent ,即所有與安全攔截有關的事件。 讓我們看看這是如何實現的:

package com.javacodegeeks.gwt.security.server.auth;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;public class CustomAuthListener implements ApplicationListener<AbstractAuthenticationEvent> {private static final Log logger = LogFactory.getLog(CustomAuthListener.class);@Overridepublic void onApplicationEvent(AbstractAuthenticationEvent event) {final StringBuilder builder = new StringBuilder();builder.append("Authentication event ");builder.append(event.getClass().getSimpleName());builder.append(": ");builder.append(event.getAuthentication().getName());builder.append("; details: ");builder.append(event.getAuthentication().getDetails());if (event instanceof AbstractAuthenticationFailureEvent) {builder.append("; exception: ");builder.append(((AbstractAuthenticationFailureEvent) event).getException().getMessage());}logger.warn(builder.toString());}}

在我們的實現中,我們僅記錄所有成功和不成功的身份驗證事件(基于LoggerListener類),但是在此處提供您自己的業務邏輯顯然很簡單。

最后,我們將創建一個GWT異步服務器端服務,該服務將向客戶端提供有關用戶及其登錄用戶名的信息。 如果您最熟悉GWT,那么理解代碼就不會有任何問題。 這是兩個接口以及該服務的具體實現:

驗證服務

package com.javacodegeeks.gwt.security.client;import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;/*** The client side stub for the RPC service.*/
@RemoteServiceRelativePath("auth")
public interface AuthService extends RemoteService {String retrieveUsername();
}

AuthServiceAsync

package com.javacodegeeks.gwt.security.client;import com.google.gwt.user.client.rpc.AsyncCallback;/*** The async counterpart of <code>AuthService</code>.*/
public interface AuthServiceAsync {void retrieveUsername(AsyncCallback<String> callback);
}

AuthServiceImpl

package com.javacodegeeks.gwt.security.server;import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.javacodegeeks.gwt.security.client.AuthService;@SuppressWarnings("serial")
public class AuthServiceImpl extends RemoteServiceServlet implements AuthService {@Overridepublic String retrieveUsername() {Authentication authentication =SecurityContextHolder.getContext().getAuthentication();if (authentication==null){System.out.println("Not logged in");return null;}else {return (String) authentication.getPrincipal();}}}

代碼很簡單。 我們使用SecurityContextHolder類來檢索當前的SecurityContext ,然后使用getAuthentication方法來獲取對基礎Authentication對象的引用。 然后,我們通過getPrincipal方法檢索用戶名(如果有)。

當然,我們必須在應用程序“ web.xml”文件中聲明特定的servlet。 這里是:

... 
<servlet><servlet-name>authServlet</servlet-name><servlet-class>com.javacodegeeks.gwt.security.server.AuthServiceImpl</servlet-class>
</servlet><servlet-mapping><servlet-name>authServlet</servlet-name><url-pattern>/gwtspringsecurityproject/auth</url-pattern>
</servlet-mapping>
...

這是整個網絡聲明文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-appPUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd"><web-app><filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- Servlets --><servlet><servlet-name>greetServlet</servlet-name><servlet-class>com.javacodegeeks.gwt.security.server.GreetingServiceImpl</servlet-class></servlet><servlet-mapping><servlet-name>greetServlet</servlet-name><url-pattern>/gwtspringsecurityproject/greet</url-pattern></servlet-mapping><servlet><servlet-name>authServlet</servlet-name><servlet-class>com.javacodegeeks.gwt.security.server.AuthServiceImpl</servlet-class></servlet><servlet-mapping><servlet-name>authServlet</servlet-name><url-pattern>/gwtspringsecurityproject/auth</url-pattern></servlet-mapping><!-- Default page to serve --><welcome-file-list><welcome-file>GwtSpringSecurityProject.html</welcome-file></welcome-file-list></web-app>

讓我們看看如何在應用程序的入口點中使用此服務。 我們在onModuleLoad方法結束之前添加以下代碼片段:

authService.retrieveUsername(new AsyncCallback<String>() {public void onFailure(Throwable caught) {dialogBox.setText("Remote Procedure Call - Failure");}public void onSuccess(String result) {nameField.setText(result);}}
);

啟動應用程序之前的最后一步是處理運行時依賴項。 Spring需要大量的庫來執行其DI魔術,因此,這是在“ war / WEB-INF / lib”文件夾中必須存在的JAR列表:

  • org.springframework.aop-3.0.5.RELEASE.jar
  • org.springframework.asm-3.0.5.RELEASE.jar
  • org.springframework.beans-3.0.5.RELEASE.jar
  • org.springframework.context-3.0.5.RELEASE.jar
  • org.springframework.core-3.0.5.RELEASE.jar
  • org.springframework.expression-3.0.5.RELEASE.jar
  • org.springframework.web-3.0.5.RELEASE.jar
  • 彈簧安全配置-3.0.5.RELEASE.jar
  • Spring安全核心-3.0.5.RELEASE.jar
  • spring-security-web-3.0.5.RELEASE.jar

復制以上所有內容之后,啟動Eclipse項目配置并嘗試訪問默認URL:

http://127.0.0.1:8888/GwtSpringSecurityProject.html?gwt.codesvr=127.0.0.1:9997

Spring Security將攔截該請求,并為您提供默認的登錄頁面。 提供如下有效憑證:

提交表單數據,您將被重定向到原始URL。 請注意,該文本字段將填充用于登錄的用戶名。

返回到Eclipse控制臺視圖,并檢查在那里打印的各種日志。 您應該看到類似以下的內容:


2010年12月12日8:45:49 PM com.javacodegeeks.gwt.security.server.auth.CustomAuthListener onApplicationEvent
警告:身份驗證事件AuthenticationSuccessEvent:CustomUserAuthentication; 詳細信息:org.springframework.security.web.authentication.WebAuthenticationDetails@fffdaa08:RemoteIpAddress:127.0.0.1; SessionId:im1fdjvdu7yw
2010年12月12日8:45:49 PM com.javacodegeeks.gwt.security.server.auth.CustomAuthListener onApplicationEvent
警告:身份驗證事件InteractiveAuthenticationSuccessEvent:CustomUserAuthentication; 詳細信息:org.springframework.security.web.authentication.WebAuthenticationDetails@fffdaa08:RemoteIpAddress:127.0.0.1; SessionId:im1fdjvdu7yw

那是所有人。 您可以在這里找到創建的Eclipse項目。 玩得開心!

相關文章 :
  • GWT 2 Spring 3 JPA 2 Hibernate 3.5教程
  • SmartGWT入門,提供出色的GWT界面
  • 建立自己的GWT Spring Maven原型
  • GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
  • 使用Spring使用Java發送電子郵件– GMail SMTP服務器示例

翻譯自: https://www.javacodegeeks.com/2010/12/securing-gwt-apps-with-spring-security.html

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

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

相關文章

用Fragment制作的Tab頁面產生的UI重疊問題

本文出處&#xff1a;http://blog.csdn.net/twilight041132/article/details/43812745 在用Fragment做Tab頁面&#xff0c;發現有時候進入應用會同時顯示多個Tab內容&#xff0c;UI發生重疊。 當應用被強行關閉后&#xff08;通過手機管家軟件手動強關&#xff0c;或系統為節省…

習題6-6 使用函數輸出一個整數的逆序數 (20 分)

本題要求實現一個求整數的逆序數的簡單函數。 函數接口定義&#xff1a; int reverse( int number );其中函數reverse須返回用戶傳入的整型number的逆序數。 我的代碼&#xff1a; int reverse( int number ) {int n number,res 0,t 0;n (n>0)?n:-n;while(n ! 0){t…

Tomcat 7上具有RESTeasy JAX-RS的RESTful Web服務-Eclipse和Maven項目

開發Web服務的RESTful方法不斷受到越來越多的關注&#xff0c;并且似乎正在將SOAP淘汰。 我不會討論哪種方法更好&#xff0c;但是我相信我們都同意REST更輕量級。 在本教程中&#xff0c;我將向您展示如何使用RESTeasy開發RESTful服務以及如何將它們部署在Tomcat服務器上。 在…

appcmd命令導入導出站點與應用程序池

在IIS7上導出所有應用程序池的方法: %windir%\system32\inetsrv\appcmd list apppool /config /xml > c:\apppools.xml 這個命令會將服務器上全部的應用程序池都導出來,但有些我們是我們不需要的,要將他們刪掉.比如: DefaultAppPoolClassic .Net AppPool如果在導入時發現同名…

卸載apache

1、運行services.msc&#xff0c;在服務中停止 apache 服務。2、運行命令行程序&#xff0c;輸入 sc delete apache&#xff0c;刪除該服務3、刪除apache文件夾。轉載于:https://www.cnblogs.com/jiangjieqim/p/5357950.html

使用wowza和xuggler將RTMP轉換為RTSP

注意&#xff1a;這是我們的“ Xuggler開發教程 ”系列的一部分。 大家好&#xff01; 在過去的三個月中&#xff0c;我們一直在進行電話會議項目。 我們認為&#xff0c;使用諸如Flex之類的技術的基于Web的應用程序將是此類要求苛刻的項目的最佳方法。 隨著軟件的復雜性和電信…

如何設置網頁標題圖標

1、先制作一個名為favicon.ico的小圖標&#xff0c;并將其放到網站根目錄下 2、在html頁面<head></head>標簽內加入&#xff1a; <link rel"shortcut icon" href"favicon.ico" />OK轉載于:https://www.cnblogs.com/moshengr/p/4600281.h…

C語言pow函數的精度問題

&#xff08;1&#xff09;pow函數返回值是double類型 &#xff08;2&#xff09;pow原型 double pow(double x,double y); (3)sqrt原型 double sqrt(double x); 當輸出時函數值賦給整型就會出錯&#xff1a; int main()d {int N 1;scanf("%d",&N);for(int i …

習題2-1 求整數均值 (10 分)

吐槽一下&#xff0c;因為少打了一個空格&#xff0c;PTA上老是不給我過&#xff0c;還一直報結果錯誤&#xff0c;誤導我好久&#xff0c;即使是吹毛求疵&#xff0c;也應該提示我格式錯誤吧&#xff01;&#xff01; 原題&#xff1a; 本題要求編寫程序&#xff0c;計算4個整…

iframe高度自適應,終于解決了

一直被iframe的高度自適應的問題困擾著&#xff0c;在項目中也是多次遇到。網上也有不少相關的代碼&#xff0c;但是總不能滿足自己的要求。在頭痛了幾次之后終于下定決心解決這個問題。 本代碼主要解決的問題是&#xff1a;最外層滾動條隨著iframe高度動態變化的問題。如果ifr…

在領域驅動的設計,貧乏的領域模型,代碼生成,依賴項注入等方面……

埃里克埃文斯&#xff08;Eric Evans&#xff09;已制定了什么是域驅動設計&#xff08;DDD&#xff09;。 Martin Fowler是DDD的大力支持者和擁護者。 這些都是非凡的名字&#xff0c;幾乎可以肯定的是&#xff0c;他們正在支持一些有價值的東西。 我不是在這里對此爭論。 也許…

Javascript模塊化工具require.js教程

轉自&#xff1a;http://www.w3cschool.cc/w3cnote/requirejs-tutorial-1.html, http://www.w3cschool.cc/w3cnote/requirejs-tutorial-2.html 隨著網站功能逐漸豐富&#xff0c;網頁中的js也變得越來越復雜和臃腫&#xff0c;原有通過script標簽來導入一個個的js文件這種方式已…

數據值、列類型和數據字段屬性

數據值&#xff1a;數值型、字符型、日期型和空值等。數據列類型 2.1 數值類的數據列類型2.2 字符串類數據列類型 2.3 日期和時間型數據數據列類型 另外&#xff0c;也可以使用整形列類型存儲UNIX時間戳&#xff0c;代替日期和時間列類型&#xff0c;這是基于PHP的web項目中常…

全文搜索Apache Lucene簡介

在本教程中&#xff0c;我想談談Apache Lucene 。 Lucene是一個開源項目&#xff0c;提供基于Java的索引和搜索技術。 使用其API&#xff0c;很容易實現全文搜索 。 我將處理Lucene Java版本 &#xff0c;但請記住&#xff0c;還有一個名為Lucene.NET的.NET端口&#xff0c;以及…

函數scanf

本節介紹輸入函數 scanf 的用法。scanf 和 printf 一樣&#xff0c;非常重要&#xff0c;而且用得非常多&#xff0c;所以一定要掌握。 概述 scanf 的功能用一句話來概括就是“通過鍵盤給程序中的變量賦值”。該函數的原型為&#xff1a; # include <stdio.h> int scanf(…

C語言中定義變量位置

C標準的問題 C89規定&#xff0c;在任何執行語句之前&#xff0c;在塊的開頭聲明所有局部變量。 即應該如下&#xff1a;定義變量只能在最開始&#xff0c;scanf等執行語句之前 int N 0;double sum 0;scanf("%d",&N);在C99以及C中則沒有這個限制&#xff0c;即…

Java中的低GC:使用原語而不是包裝器

總覽 有兩個很好的理由在可能的地方使用原語而不是包裝器。 明晰。 通過使用原語&#xff0c;您可以清楚地知道null值是不合適的。 性能。 使用原語通常更快。 清晰度通常比性能更重要&#xff0c;并且是使用它們的最佳理由。 但是&#xff0c;本文討論了使用包裝程序對性能…

C# 連接Oracle數據庫以及一些簡單的操作

拖了很久今天終于在博客園寫了自己第一篇隨筆&#xff1a; 話不多說&#xff0c;我們直接進入正題&#xff1a; 1.連接數據庫 using (OracleConnection conn new OracleConnection("data source192.168.97.60/orcl;User Idabc;Passwordabc;")) { …

markdownb編輯器

這是H1 這是H2 這是H3 這是一個標題。 這是第一行列表項。這是第二行列表項。給出一些例子代碼&#xff1a; return shell_exec("echo $input | $markdown_script"); 轉載于:https://www.cnblogs.com/xcl461330197/p/4605163.html

Java Secret:使用枚舉構建狀態機

總覽 Java中的枚舉比許多其他語言更強大&#xff0c;這可能導致令人驚訝的用途。 在本文中&#xff0c;我概述了Java 枚舉的一些單獨功能&#xff0c;并將它們組合在一起形成一個狀態機。 單例和實用程序類的枚舉 您可以非常簡單地將枚舉用作Singleton或Utility。 enum Si…