整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Springboot+Shiro 基于URL 動態控

          Springboot+Shiro 基于URL 動態控制權限

          言:

          權限控制有 注解的方式,jsp shiro標簽的方式,還有url 動態控制的方式。這里我使用最后一種方式來控制權限

          思路:

          0.利用 PathMatchingFilter 攔截器

          1.根據用戶名 來查詢角色,

          2.根據角色查詢權限

          3.獲取請求的url

          4判斷 根據用戶名查詢的權限 是否包括 請求的url

          5.如果包括 則 放行,不包括重定向到 未授權界面

          package com.example.springboot.shiro.core.shiro.filter;
          
          import com.example.springboot.shiro.common.utils.SpringContextUtil;
          import com.example.springboot.shiro.core.shiro.token.TokenManager;
          import com.example.springboot.shiro.user.entity.Upermission;
          import com.example.springboot.shiro.user.service.LoginService;
          import org.apache.shiro.SecurityUtils;
          import org.apache.shiro.authz.UnauthorizedException;
          import org.apache.shiro.subject.Subject;
          import org.apache.shiro.web.filter.PathMatchingFilter;
          import org.apache.shiro.web.util.WebUtils;
          import org.springframework.beans.factory.annotation.Autowired;
          
          import javax.servlet.ServletRequest;
          import javax.servlet.ServletResponse;
          import java.util.List;
          
          /**
           *  權限 攔截策略
           */
          public class URLPathMatchingFilter extends PathMatchingFilter {
              @Autowired
              LoginService loginService;
          
              @Override
              protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
          
                    if (loginService==null){
                        loginService=SpringContextUtil.getContext().getBean(LoginService.class);
                    }
                  //請求的url
                  String requestURL=getPathWithinApplication(request);
                  System.out.println("請求的url :"+requestURL);
                  Subject subject=SecurityUtils.getSubject();
                  if (!subject.isAuthenticated()){
                      // 如果沒有登錄, 直接返回true 進入登錄流程
                      return  true;
                  }
                  String email=TokenManager.getEmail();
                  List<Upermission> permissions=loginService. upermissions(email);
          
                  boolean hasPermission=false;
                  for (Upermission url : permissions) {
          
                        if (url.getUrl().equals(requestURL)){
                            hasPermission=true;
                            break;
                        }
                  }
                  if (hasPermission){
                      return true;
                  }else {
                      UnauthorizedException ex=new UnauthorizedException("當前用戶沒有訪問路徑" + requestURL + "的權限");
                      subject.getSession().setAttribute("ex",ex);
                      WebUtils.issueRedirect(request, response, "/unauthorized");
                      return false;
          
                  }
          
              }
          }
          

          配置 : ShiroConfiguration(shiro 配置類)

          package com.example.springboot.shiro.core.shiro.config;
          
          import java.util.HashMap;
          import java.util.LinkedHashMap;
          import java.util.Map;
          
          import com.example.springboot.shiro.core.shiro.filter.KickoutSessionControlFilter;
          import com.example.springboot.shiro.core.shiro.filter.SessionControlInterceptor;
          import com.example.springboot.shiro.core.shiro.filter.SessionFilter;
          import com.example.springboot.shiro.core.shiro.filter.URLPathMatchingFilter;
          import com.example.springboot.shiro.core.shiro.token.SampleRealm;
          import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
          import org.apache.shiro.codec.Base64;
          import org.apache.shiro.mgt.SecurityManager;
          import org.apache.shiro.spring.LifecycleBeanPostProcessor;
          import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
          import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
          import org.apache.shiro.web.mgt.CookieRememberMeManager;
          import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
          import org.apache.shiro.web.servlet.SimpleCookie;
          import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
          import org.crazycake.shiro.RedisManager;
          import org.crazycake.shiro.RedisSessionDAO;
          import org.springframework.beans.factory.annotation.Value;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.crazycake.shiro.RedisCacheManager;
          import org.springframework.data.redis.core.RedisTemplate;
          
          import javax.servlet.Filter;
          
          @Configuration    //Shiro配置類
          public class ShiroConfiguration {
              @Value("${spring.redis.host}")
              private String host;
          
              @Value("${spring.redis.port}")
          
              private int port;
              @Value("${spring.redis.timeout}")
              private int timeout;
          
              @Bean
              public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
                  return new LifecycleBeanPostProcessor();
              }
          
          
              /**
               * ShiroFilterFactoryBean 處理攔截資源文件問題。
               * 注意:單獨一個ShiroFilterFactoryBean配置是或報錯的,因為在
               * 初始化ShiroFilterFactoryBean的時候需要注入:SecurityManager
               * <p>
               * Filter Chain定義說明
               * 1、一個URL可以配置多個Filter,使用逗號分隔
               * 2、當設置多個過濾器時,全部驗證通過,才視為通過
               * 3、部分過濾器可指定參數,如perms,roles
               */
              @Bean
              public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
                  System.out.println("ShiroConfiguration.shirFilter()");
                  ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
          
                  // 必須設置 SecurityManager
                  shiroFilterFactoryBean.setSecurityManager(securityManager);
                  // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
                  shiroFilterFactoryBean.setLoginUrl("/login");
                  // 登錄成功后要跳轉的鏈接(沒用,在js中跳轉了)
                  shiroFilterFactoryBean.setSuccessUrl("/index");
                  //未授權界面
                  shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
                  //攔截器.
                  Map<String, String> filterChainDefinitionMap=new LinkedHashMap<String, String>();
                  //自定義攔截器
                  Map<String, Filter> filtersMap=new LinkedHashMap<String, Filter>();
                  //限制同一帳號同時在線的個數。
                  filtersMap.put("kickout", kickoutSessionControlFilter());
                  //訪問權限配置
                  filtersMap.put("requestURL", getURLPathMatchingFilter());
          
                  shiroFilterFactoryBean.setFilters(filtersMap);
                 /* 配置映射關系*/
                  //authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問
                  filterChainDefinitionMap.put("/login", "anon");
                  filterChainDefinitionMap.put("/index", "authc");
                  filterChainDefinitionMap.put("/css/**", "anon");
                  filterChainDefinitionMap.put("/js/**", "anon");
                  filterChainDefinitionMap.put("/updateSelf", "authc");
                  filterChainDefinitionMap.put("/updatePswd", "authc");
                  filterChainDefinitionMap.put("/mypermission", "authc");
                  filterChainDefinitionMap.put("/kickout", "anon");
                  filterChainDefinitionMap.put("/list", "authc");
                  filterChainDefinitionMap.put("/online", "authc");
                  filterChainDefinitionMap.put("/role", "authc");
                  filterChainDefinitionMap.put("/Roleassignment", "authc");
                  filterChainDefinitionMap.put("/permissionlist", "authc");
                  filterChainDefinitionMap.put("/PermissionAssignment", "authc");
          
                  /*加入自定義過濾器*/
                  filterChainDefinitionMap.put("/**", "kickout");
                  //下面的配置路徑 都需要在上面配置 authc 否則訪問不到filter
                  filterChainDefinitionMap.put("/online","requestURL");
                  filterChainDefinitionMap.put("/list", "requestURL");
                  filterChainDefinitionMap.put("/role", "requestURL");
                  filterChainDefinitionMap.put("/Roleassignment", "requestURL");
                  filterChainDefinitionMap.put("/permissionlist", "requestURL");
                  filterChainDefinitionMap.put("/PermissionAssignment", "requestURL");
          
          
                  shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
                  return shiroFilterFactoryBean;
          
              }
          
              /**
               *   訪問 權限 攔截器
               * @return
               */
              public URLPathMatchingFilter getURLPathMatchingFilter() {
                  return new URLPathMatchingFilter();
              }
          
              /**
               * 自定義域
               *
               * @return
               */
              @Bean
              public SecurityManager securityManager() {
                  DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
                  //設置realm.
                  securityManager.setRealm(getDatabaseRealm());
          
                  // 自定義緩存實現 使用redis
                  securityManager.setCacheManager(cacheManager());
                  securityManager.setSessionManager(sessionManager());
                  //注入記住我管理器;
                  securityManager.setRememberMeManager(rememberMeManager());
                  return securityManager;
              }
          
              /**
               * 授權&認證
               *
               * @return
               */
              @Bean
              public SampleRealm getDatabaseRealm() {
                  SampleRealm myShiroRealm=new SampleRealm();
                  System.out.println("myShiroRealm");
                  myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
                  return myShiroRealm;
              }
          
          
              /**
               * 憑證匹配器
               * (由于我們的密碼校驗交給Shiro的SimpleAuthenticationInfo進行處理了
               * 所以我們需要修改下doGetAuthenticationInfo中的代碼;
               * )
               *
               * @return
               */
              @Bean
              public HashedCredentialsMatcher hashedCredentialsMatcher() {
                  HashedCredentialsMatcher hashedCredentialsMatcher=new HashedCredentialsMatcher();
          
                  hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:這里使用MD5算法;
                  //  hashedCredentialsMatcher.setHashIterations(2);//散列的次數,比如散列兩次,相當于 md5(md5(""));
          
                  return hashedCredentialsMatcher;
              }
          
          
              /**
               * 開啟shiro aop注解支持.
               * 使用代理方式;所以需要開啟代碼支持;
               *
               * @param securityManager
               * @return
               */
              @Bean
              public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
                  AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor=new AuthorizationAttributeSourceAdvisor();
                  authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
                  return authorizationAttributeSourceAdvisor;
              }
          
              /**
               * cacheManager 緩存 redis實現
               * 使用的是shiro-redis開源插件
               *
               * @return
               */
              public RedisCacheManager cacheManager() {
                  RedisCacheManager redisCacheManager=new RedisCacheManager();
                  redisCacheManager.setRedisManager(redisManager());
                  return redisCacheManager;
              }
          
          
              /**
               * 配置shiro redisManager
               * 使用的是shiro-redis開源插件
               *
               * @return
               */
              public RedisManager redisManager() {
                  RedisManager redisManager=new RedisManager();
                  redisManager.setHost(host);
                  redisManager.setPort(port);
                  redisManager.setExpire(1800);// 配置緩存過期時間
                  redisManager.setTimeout(timeout);
                  // redisManager.setPassword(password);
                  return redisManager;
              }
          
              /**
               * Session Manager
               * 使用的是shiro-redis開源插件
               */
              @Bean(name="sessionManager")
              public DefaultWebSessionManager sessionManager() {
                  DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
                  sessionManager.setSessionDAO(redisSessionDAO());
                  return sessionManager;
              }
          
              /**
               * RedisSessionDAO shiro sessionDao層的實現 通過redis
               * 使用的是shiro-redis開源插件
               */
              @Bean
              public RedisSessionDAO redisSessionDAO() {
                  RedisSessionDAO redisSessionDAO=new RedisSessionDAO();
          
                  redisSessionDAO.setRedisManager(redisManager());
                  return redisSessionDAO;
              }
          
              /**
               * cookie管理對象;記住我功能
               *
               * @return
               */
              public CookieRememberMeManager rememberMeManager() {
                  CookieRememberMeManager cookieRememberMeManager=new CookieRememberMeManager();
                  cookieRememberMeManager.setCookie(rememberMeCookie());
                  //rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位)
                  cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
                  return cookieRememberMeManager;
              }
          
              /**
               * cookie對象;
               *
               * @return
               */
              public SimpleCookie rememberMeCookie() {
                  //這個參數是cookie的名稱,對應前端的checkbox的name=rememberMe
                  SimpleCookie simpleCookie=new SimpleCookie("rememberMe");
                  //<!-- 記住我cookie生效時間30天 ,單位秒;-->
                  simpleCookie.setMaxAge(2592000);
                  return simpleCookie;
              }
          
              /**
               * 限制同一賬號登錄同時登錄人數控制
               *
               * @return
               */
              public KickoutSessionControlFilter kickoutSessionControlFilter() {
                  KickoutSessionControlFilter kickoutSessionControlFilter=new KickoutSessionControlFilter();
                  //使用cacheManager獲取相應的cache來緩存用戶登錄的會話;用于保存用戶—會話之間的關系的;
                  //這里我們還是用之前shiro使用的redisManager()實現的cacheManager()緩存管理
                  //也可以重新另寫一個,重新配置緩存時間之類的自定義緩存屬性
                  kickoutSessionControlFilter.setCacheManager(cacheManager());
                  //用于根據會話ID,獲取會話進行踢出操作的;
                  kickoutSessionControlFilter.setSessionManager(sessionManager());
                  //是否踢出后來登錄的,默認是false;即后者登錄的用戶踢出前者登錄的用戶;踢出順序。
                  kickoutSessionControlFilter.setKickoutAfter(false);
                  //同一個用戶最大的會話數,默認1;比如2的意思是同一個用戶允許最多同時兩個人登錄;
                  kickoutSessionControlFilter.setMaxSession(1);
                  //被踢出后重定向到的地址;
                  kickoutSessionControlFilter.setKickoutUrl("kickout");
                  return kickoutSessionControlFilter;
              }
          }

          未授權 異常捕獲:

          Shiro 是 JAVA 世界中新近出現的權限框架,較之 JAAS 和 Spring Security,Shiro 在保持強大功能的同時,還在簡單性和靈活性方面擁有巨大優勢。本文就帶領讀者一睹 Shiro 的風采。

          可能大家早先會見過 J-security,這個是 Shiro 的前身。在 2009 年 3 月初之前,這個安全框架叫做 J-security,由于某些原因,更名為 Shiro(或者 Ki,意為 Fortress),是 Apache 的孵化項目,鑒于本文編寫時 Shiro 的還沒有正式發布的版本,本文使用的是 Jsecurity 的穩定版本 0.9,本文中 Shiro 等同于 Jsecurity。

          本文將涉及 Shiro 的整體框架、安全模型、關鍵概念類,同時給出了 Shiro 以及 Grails Shiro Plugin 的使用示例,可以下載文中使用的源代碼。

          本文代碼的開發環境:

          • Jsecurity 0.9
          • Grails 1.2.0
          • Grails Shiro Plugin 1.0.1
          • SpringSource Tool Suite 2.3

          Shiro 是一個強大而靈活的開源安全框架,能夠非常清晰的處理認證、授權、管理會話以及密碼加密。如下是它所具有的特點:

          1. 易于理解的 Java Security API;
          2. 簡單的身份認證(登錄),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
          3. 對角色的簡單的簽權(訪問控制),支持細粒度的簽權;
          4. 支持一級緩存,以提升應用程序的性能;
          5. 內置的基于 POJO 企業會話管理,適用于 Web 以及非 Web 的環境;
          6. 異構客戶端會話訪問;
          7. 非常簡單的加密 API;
          8. 不跟任何的框架或者容器捆綁,可以獨立運行。

          目前還有其他出現較早的安全框架,比如 JAAS,Spring Security。

          JAAS —面世的時間最早,但是鑒于其在使用上有很大的限制,很少有人真正的使用它。可以說它不是一個好的應用程序級別的安全框架;

          Spring Security —目前是 Java 安全框架領域當之無愧的老大,已經非常成熟了;如果使用 Spring 框架,可以首選 Spring Security,但是對于單應用來說,Shiro 更顯簡單方便。

          下面就開始我們的 Shiro 之旅吧!

          整體架構

          首先,我們來看看的 Shiro 的整體架構,見下圖:

          圖 1. 整體架構

          從上圖可以看出,Shiro 主要有四個組件:

          1. SecurityManager
          2. 典型的 Facade,Shiro 通過它對外提供安全管理的各種服務。
          3. Authenticator
          4. 對“Who are you ?”進行核實。通常涉及用戶名和密碼。
          5. 這個組件負責收集 principals 和 credentials,并將它們提交給應用系統。如果提交的 credentials 跟應用系統中提供的 credentials 吻合,就能夠繼續訪問,否則需要重新提交 principals 和 credentials,或者直接終止訪問。
          6. Authorizer
          7. 身份份驗證通過后,由這個組件對登錄人員進行訪問控制的篩查,比如“who can do what”, 或者“who can do which actions”。Shiro 采用“基于 Realm”的方法,即用戶(又稱 Subject)、用戶組、角色和 permission 的聚合體。
          8. Session Manager
          9. 這個組件保證了異構客戶端的訪問,配置簡單。它是基于 POJO/J2SE 的,不跟任何的客戶端或者協議綁定。

          Shiro 的認證和簽權可以通過 JDBC、LDAP 或者 Active Directory 來訪問數據庫、目錄服務器或者 Active Directory 中的人員以及認證 / 簽權信息。SessionManager 通過會話 DAO 可以將會話保存在 cache 中,或者固化到數據庫或文件系統中。

          安全模型

          從 Shiro 的框架圖,已經能夠體會到這個工具的簡單了。下面讓我們來看看 Shiro 是如何工作的。先了解一下它的安全模型吧!見下圖:

          圖 2. 安全模型

          上圖中,涉及了 Shiro 的五個概念:

          • Subject 是安全領域術語,除了代表人,它還可以是應用。在單應用中,可將其視為 User 的同義詞。
          • Principal 是 Subject 的標識,一般情況下是唯一標識,比如用戶名。
          • Role 和 Permission 分別代表了不同粒度的權限,從上圖中可以看出 Role 的粒度更大些,Permission 代表了系統的原子權限,比如數據的修改、刪除權限。對于簡單的權限應用,可以不需要 Permission。
          • Realm 是一個執行者,負責真正的認證和鑒權。

          實現應用的安全模塊的關鍵在于:定義合適的 role 和 permission,這就需要遵循如下原則:

          1. role 沒有實質內容,只是代表一組 permission,目的是為了管理的方便,一般都是動態定義;
          2. permission 一般都是預先定義好的,不允許動態改變,除非源代碼改動,它才會變化,它是整個安全模塊的基礎;
          3. 要使 permission 也能動態定義,并非不可能,但是這將使鑒權非常復雜,甚至可能導致鑒權語句遍布整個程序,得不償失;
          4. 當然有一個例外:如果知道 permission 動態定義的規則和鑒權規則,如 Grails 的 fileter 中“${controllerName}:${actionName}:${params.id}”也可實現 permission 的動態定義

          關鍵概念類

          理解 Shiro 的架構和安全模型了,我們來看看更具體些的內容。下圖顯示了 Shiro 中的關鍵概念類(參考資料 -- JSecurity Mini Guide)。

          圖 3. 關鍵類

          AuthenticationToken 和 AuthenticationInfo

          前者在認證前使用,描述認證所需的信息,最常用的就是 username 和 password 對;后者在認證后使用,內容同前,但是表示已經經過認證的信息。

          RememberMe

          代表的是一種可能狀態,并不表示該 Subject 已經經過了認證。對于一些普通的操作,這種可能狀態并無大礙,但一旦涉及安全敏感的操作,必須經過認證。

          Credentials 和 CredentialsMatcher

          Credentials 是 Subject 的證書,在認證時使用,最常用的就是 password。在通常情況下,為了安全起見,Subject 的 credentials 都需要加密保存,于是 CredentialsMatcher 的作用就體現出來了,見下圖:

          圖 4. CredentialsMatcher 的作用

          這里 CredentialsMatcher 需要將加密后的證書跟用戶登錄時提供的證書進行比對,完成認證的過程。

          PAM=Pluggable Authentication Modules

          在有多個 Realm 的時候使用。由認證策略決定認證結果,即 PAM=Relams + 認證策略。一般的策略有 3 種:AllSuccessful、AtLeastOneSuccessful 和 FirstSuccessful。

          AuthorizationInfo

          可以看成是 Role + Permission 的組合體。

          PermissionResolver 和 Permission

          它們之間的關系如下:

          圖 5. PermissionResolver 和 Permission 的關系

          在 Shiro 中,權限被轉化為一種字符串描述(字符串分級表示,稱之為 WildcardPermission),從而將權限轉化為類似于對象 equals 的操作(Shiro 中的 implies 方法)。

          內置的權限有 2 個:

          • AllPermission,總是返回 true
          • WildcardPermission,權限字符串的表示方式。

          這里重點聲明一下。WildcardPermission 是 Shiro 的精妙之處,我們可以將權限表示成字符串,這樣對權限的控制可以不拘泥于物理存儲,比如對 messagge 類具有修改和刪除權限可以標識為:message:update,delete:*,其中‘ * ’表示所有;第一級分隔符為‘ : ’;第二級分隔符為‘ , ’,而對于權限字符串的解釋完全可以由應用自己來定。

          如果要比較權限字符串,可以使用 permission1.implies(permission2),它分別比較對應位置的字符串,在如下情況中,結果會返回 true:

          • permission1 中的子串有 * 或 permission1 子串==permission2 子串;
          • permission1 無子串,permission2 有;
          • permission1 有子串,permission2 無,permission1 的所有子串都是 *。

          總的說來,Shiro 中的 Permission 需要注意如下內容:

          1. 權限的比較實際是字符串的比較,只不過是考慮到了字符串的分級
          2. 字符串的分級劃分完全由使用者自己決定,Shiro 的慣例是 3 級:資源 : 操作 : 實例。
          3. 字符串的使用必須一致,分隔符之間不要有空格,避免無意間引入的不一致。如:定義使用“file : create, update : 1”,而驗證使用“file : update”,那么分解之后一個是“ update ”,一個是“ update”,因空格而引起不等。

          Realm

          這是一個實際訪問安全實體的組件,一般是應用相關的,跟數據源的關系是 1-1。它負責完成認證和鑒權,getAuthenticationInfo 代表了 login 的嘗試,鑒權方法則由 Authorizer 繼承而來。此處也體現了 Shiro 代碼的另一個特點,通過繼承來擴充功能。以常用的 JdbcRealm 為例,其繼承鏈如下:

          圖 6. JdbcRealm 的繼承鏈

          Session

          它關聯一個 Subject 的上下文,其作用類似于在 HttpSession 中保存用戶標識,session 一旦過期,則重新登錄。Shiro 的 Session 是獨立的,其目的是做到環境無關性。為了利用 Web 環境中,Shiro 實現了一個直接使用 HttpSession 的 WebSession。

          SecurityManager

          這是一個 Fa?ade 接口,=Authenticator + Authorizer + SessionFactory。在整體框架圖中已經看到了它在 Shiro 中所處的位置。其特點同 Realm,一樣是使用繼承不斷地擴充功能。對于 Web 應用一般使用 DefaultWebSecurityManager。

          Filter

          在 Web 環境下使用 filter 進行認證和權限檢查是毋庸置疑的,而 Shiro 的特點則在于由一個主 Filter 將一群子 filter 串起來:

          圖 7. Filter 的作用

          在實際使用時,須注意:

          1. web.xml 中只需配置 JSecurityFilter。對于 Spring 應用,則使用 SpringJSecurityFilter;
          2. 子 filter 作為主 filter 的配置參數值出現,特點是:順序相關
          • 對于多個 URL,驗證順序是由上至下,類似 Exception 的匹配。因此,使用順序應該是由細到粗。
          • 對于同一 URL,子 filter 的驗證順序是從左至右的 AND 操作。
          1. 如果配置值中含有分隔符,如 Permission,就需要使用引號來轉義。

          Subject

          subject 代表了一個用戶的狀態和操作,它提供了所有安全相關的操作,包括認證和簽權。可以將其視為另一種形式的 Fa?ade。缺省實現是將這些操作委派給其內部包含的 SecurityManager。

          Configuration

          configuration 負責將所有這些組件串起來,最終創建 SecurityManager。在 Shiro 中,缺省格式是 ini。整個配置關系如下圖:

          圖 8. 配置關系

          其中:

          • JSecurityFilter 創建 Configuration 實例,并將 ini 參數值傳給 Configuation。在 Spring 環境中,分別使用 SpringJSecurityFilter 和 SpringIniWebConfiguration。
          • Configuration 實際就是 SecurityManager 的 Factroy,對 SpringIniWebConfiguration 而言,它需要知道 SecurityManager 的 BeanName,該值由 SpringJSecurityFilter 的初始化參數“securityManagerBeanName”值決定。即 SpringJSecurityFilter,實際有兩個初始化參數:
          • config,是 ini 配置文件內容
          • securityManagerBeanName,是 SecurityManager 的 BeanName

          SecurityUtils

          這是 Shiro 中最重要的工具類,由它可以方便地獲得 Subject 和 SecurityManager。

          雜項

          • AOP,提供 AOP 方面的支持,實現對某個類某個方法的攔截,從而使權限控制延伸至類的方法。
          • Cache,提供緩存支持
          • Codec,提供編碼方面的支持
          • Crypto,提供加密支持
          • IO,從多個資源位置讀寫原始數據
          • JNDI,提供 jndi 支持
          • util,工具類支持
          • 標簽類,用于 Web 頁面

          典型使用

          對 Shiro 有了一個感官認識后,下面我們就親自動手試試這個框架吧!下面給大家舉了兩個使用案例。

          在開始案例的學習之前,先作好準備工作 -- 獲得 Shiro 相關的 jar 包,獲取途徑有兩種:

          1. 直接到 J-security 的網站上 下載,本文用到的就是這個;
          2. 由于 Shiro 目前是 Apache 的孵化項目,還沒有發布正式的版本,但是我們可以到 Subversion 上下載代碼,之后使用 Maven 構建
          3. mkdir shiro
          4. cd shiro
          5. svn co https://svn.apache.org/repos/asf/incubator/shiro/trunk/
          6. mvn install

          之后會得到 shiro-all-1.0-incubating-SNAPSHOT.jar,就可以使用 Shiro 了。

          示例一:讓 Shiro 為你的應用服務

          這個案例中,我們使用 Grails 向大家講述 Shiro 的使用。我們要實現如下功能:

          1. 用戶登錄后方可進入系統;
          2. 假定一個 message 的安全內容,用戶可以創建 message 的內容,但是如果需要修改 / 刪除 message 的內容就必須具有相應的權限;
          3. Admin 具有所有的權限;
          4. message 的權限跟角色關聯。

          示例程序執行的流程如下:

          圖 9 程序執行的流程

          從上圖中可以看到,任何人要訪問應用中受保護的 URL,首先要通過 Filter 檢查用戶是否經過認證;對于沒有認證的用戶會將訪問定向到登錄頁面;對于已經認證的用戶,會對用戶進行鑒權,這個用戶是否具有訪問其所提交的 URL 的權限;而管理員可以給角色授權。

          好了,開始程序的編寫啦!

          創建安全領域類

          最常見的就是 User、Role 和 Permission,見清單 1。

          清單 1. User/Role/Permission 的 Domain class

          class User {

          String username

          String password

          static hasMany=[roles: Role]

          static belongsTo=Role

          ……

          }

          class Role {

          String rolename

          static hasMany=[users: User, permissions: Permission]

          ……

          }

          class Permission {

          String permission

          static hasMany=[roles: Role]

          static belongsTo=Role

          ……

          }

          這里使用了最簡單的情形,即權限傳遞結構為:Permission -> Role -> User。通常情況下,Permission 也可以分配給單個 User。

          創建一個安全實體

          實體名為 message,見清單 2。只有經過授權的用戶才能對這個實體進行修改和刪除。

          清單 2. message 的 Domain class

          class Message {

          String details

          User user

          static constraints={

          }

          }

          配置 web.xml

          清單 3. 在 web.xml 加入 SecurityFilter 的內容:

          <filter>

          <filter-name>SecurityFilter</filter-name>

          <filter-class>

          org.jsecurity.spring.SpringJSecurityFilter

          </filter-class>

          <init-param>

          <param-name>securityManagerBeanName</param-name>

          <param-value>jsecSecurityManager</param-value>

          </init-param>

          </filter>

          <filter-mapping>

          <filter-name>SecurityFilter</filter-name>

          <url-pattern>/*</url-pattern>

          </filter-mapping>

          這里需要注意:

          • 這個 Filter 應該在 Grails 的 web.xml 中所有缺省的 Filter 最后;
          • url-pattern 不要使用“/**”,因為這樣會造成登錄頁的 css 和圖片無法訪問。解決辦法,可以通過遵循“只能通過 Controller/Action 訪問”這個規則,并使用 Grails 的 Filter 機制,可以保證所有安全 URL 不被非法訪問。

          創建 realm

          清單 4. conf/spring/resources.groovy

          beans={

          credentialMatcher(

          org.jsecurity.authc.credential.Sha1CredentialsMatcher) {

          storedCredentialsHexEncoded=true

          }

          permissionResolver(

          org.jsecurity.authz.permission.WildcardPermissionResolver)

          realm(org.jsecurity.realm.jdbc.JdbcRealm){

          permissionResolver=ref("permissionResolver")

          dataSource=ref("dataSource")

          permissionsLookupEnabled=true

          permissionsQuery="select permission from

          permission, role_permissions, role where

          permission.id=permission_id and role_id=role.id and rolename=?"

          userRolesQuery="select rolename from role, role_users, user

          where role.id=role_id and user_id=user.id and username=?"

          authenticationQuery="select password from user where username=?"

          }

          jsecSecurityManager(

          org.jsecurity.web.DefaultWebSecurityManager) {

          bean ->bean.destroyMethod="destroy"

          realms=[ ref("realm") ]

          }

          }

          這里使用了 JdbcRealm,同時根據應用情況修改了相應的 SQL。如果允許 Permission 直

          接分配給 User,即 Permission 和 User 之間是多對多關系,那么 permissionsQuery 應該使用 union,即“role 相關 permission union user 相關 permission”。對于 User 有多個 Role 的情況,JdbcRealm 會循環得出總的結果。

          安全守護神:SecurityFilters

          下面就是我們的安全守護神:SecurityFilters,這里遵循 Grails 的 Filter 語法。見清單 5。

          清單 5. SecurityFilters

          import org.jsecurity.SecurityUtils

          class SecurityFilters {

          def filters={

          authc(controller:'*', action:'*', ) {

          before={

          if(controllerName!='auth'){

          def subject=SecurityUtils.subject

          if (!subject.authenticated) {

          redirect(

          controller: 'auth',

          action: 'login',

          params: [

          targetUri: request.forwardURI - request.contextPath

          ])

          return false

          }

          }

          }

          }

          admin(controller: 'user|role|permission', action: '*'){

          before={

          def subject=SecurityUtils.subject

          if(!subject.hasRole('admin')){

          redirect(controller: 'auth', action: 'unauthorized')

          return false

          }

          }

          }

          editmessage(controller: 'message', action: 'update|delete'){

          before={

          def subject=SecurityUtils.subject

          if(!subject.isPermitted(

          "${controllerName}:${actionName}:${params.id}")){

          redirect(controller: 'auth', action: 'unauthorized')

          return false

          }

          }

          }

          }

          }

          代碼中 :

          • authc 表示的是所有用戶對應用系統的任何訪問都要經過 auth 認證,對于沒有認證的用戶的訪問會重定向到登錄界面;
          • admin 表示的是屬于 admin 角色的用戶對 user/role/permission 具有所有權限,對于非 admin 角色的用戶會對其提示沒有 user/role/permission 的訪問權限;
          • editmessage 表示當用戶對 message 進行修改或者刪除的時候對其進行鑒權,只有具有 message 的 update/delete 權限的用戶才能對 message 進行修改。

          在上述代碼中還可以看出,我們通常可以由 SecurityUtils 為出發點獲得 Subject 和 SecurityManager。需要注意的是,認證的 Filter(authc)要打頭陣。

          認證的代碼

          清單 6. 認證代碼

          def signIn={

          // 創建 AuthenticationToken

          def authToken=new UsernamePasswordToken(

          params.username,

          params.password)

          if (params.rememberMe) {

          authToken.rememberMe=true

          }

          try{

          // 使用 SecurityManager 的 login 登錄

          this.jsecSecurityManager.login(authToken)

          flash.message=message(code: "$params.username")

          def targetUri=params.targetUri ?: "/"

          log.info "Redirecting to '${targetUri}'."

          redirect(uri: targetUri)

          }

          catch (AuthenticationException ex){

          // 如果出現異常,顯示出錯信息

          log.info "Authentication failure for user '${params.username}'."

          flash.message=message(code: "login.failed")

          def m=[ username: params.username ]

          if (params.rememberMe) {

          m['rememberMe']=true

          }

          if (params.targetUri) {

          m['targetUri']=params.targetUri

          }

          redirect(action: 'login', params: m)

          }

          }

          授權部分很簡單,即對安全實體進行 CRUD。其中 Permission 的權限字符串根據實際情況形成,在本例中:

          • 如果對所有 message 具有修改權限,權限字符串可以為:message:delete,update:*;
          • 如果針對某一個 message 具有修改權限,權限字符串可以為:message:update,delete:messageid。

          示例二:使用 Shiro Plugin 快速構建安全模塊

          在示例一中,所有的代碼都是自己手動寫的,這就對初學者要求有些高了。但可喜的是 Grails 社區有了 Shiro 的 plugin,讓我們的工作變得非常簡單。同樣示例一的功能,看看 plugin 能夠給我們帶來什么樣的驚喜?

          使用步驟如下:

          1. 安裝 Shiro Plugin,在你的 grails 項目中運行:grails install-plugin shiro,會創建 grails-app/realms 目錄,并提供如下新的 Grails 命令:
          • grails create-auth-controller,創建 AuthController 以及登錄窗口,Controller 提供了登錄、登出和權限驗證失敗處理等 Action。
          • grails create-db-realm,創建一個訪問數據庫的 Realm
          • grails create-ldap-realm,創建一個訪問 ldap 的 Realm
          • grails create-wildcard-realm,創建一個訪問數據庫的 Realm,但使用的是 Shiro 的 WildcardPermission。
          • grails quick-start,它是 create-auth-controller 和 create-db-realm 的集合體,是 Shiro 的快速入門,在接下來的內容中將詳細介紹它的使用。
          1. 下面進行 Shiro 快速入門。在 grails 項目的目錄下執行:grails quick-start,這個命令會創建如下內容:
          • 在 grails-app/realms 下創建 ShiroDbRealm,這個 realm 是訪問控制的信息庫,用來決定一個用戶有權訪問哪些內容;
          • 在 grails-app/domain 創建 ShiroRole.groovy 和 ShiroUser.groovy;
          • 在 grails-app/controllers 下創建 AuthController,這里提供了登錄和退出的 action;
          • 在 grails-app/views 下創建 auth 文件夾以及 login.gsp;
          • 在 grails-app/conf/ 下創建 SecurityFilters.groovy,這里管理著對所有 controller 和 action 的訪問控制。
          1. 啟動程序,當訪問 controller 的時候,頁面就會重定向到登錄頁面。但是這個時候是無法登錄,因為我們沒有添加用戶。
          2. 進入到 grails-app/conf/ 修改 BootStrap.groovy,
          3. 清單 7. 修改后的 BootStrap.groovy

          def init={ servletContext ->

          def user=new User(username: "user",

          passwordHash: new Sha1Hash("user").toHex())

          user.save()

          def role=new Role(name:"admin").addToUsers(user).save()

          }

          1. 重新啟動程序,就能使用 user/user 登陸了。
          2. 在 plugin 缺省創建的 SecurityFilters 中使用了對所有 URL 進行 before 攔截,但是我們根據實際情況進行修改,例如我們要示例一的 filter 內容,就可以做如下更改:
          3. 清單 8. 更改后的 SecurityFilters

          auth(controller: "*", action: "*"){

          before={

          accessControl{true}

          }

          }

             management(controller: "user|role|permission", action: "*"){

          before={

          accessControl{role("admin")}

          }

          }

          message(controller: "message", action: "delete|update"){

          before={

          accessControl{   

                 permission("message:${actionName}:${params.id}")

          }

          }

          }

          1. 看到這里,讀者可能已經注意到了,這里的代碼比示例一中的 Filter 的代碼簡單的許多。對,Shiro 插件已經將示例一中的類似代碼封裝到 ShiroGrailsPlugin.groovy 中了,我們使用的時候只需要:
          2. 調用 accessControl 方法,該方法的參數可以是 Map、Closure 或者 Map+Closure;
          3. 使用 role( …… ),驗證訪問對象是否具有相應的角色;
          4. 使用 permission( …… ),驗證訪問對象是否具有相應的 Permission。
          5. 授權部分內容參見上一示例,這里不做冗述。
          6. Shiro Plugin 中除了為我們提供了上述方便之外,還提供了一些常用的 taglib 來增強用戶界面 , 這些 taglib 都在 pluginPath/grails-app/taglib /ShiroTagLib.groovy 中定義,我們可以直接在 gsp 中使用它們。
          7. 比如,只有具有修改權限的用戶才能夠看到一些修改類的按鈕顯示,可以這樣寫:
          8. 清單 9. Taglib 的使用

          <shiro:hasPermission permission="message:update,delete">

          <span class="button">

          <g:actionSubmit class="edit" value="Edit" />

          </span>

          <span class="button">

          <g:actionSubmit class="delete"

          onclick="return confirm('Are you sure?');"

          value="Delete" />

          </span>

          </shiro:hasPermission>

          1. 如下是經常使用到的 Tag:
          • principal,輸出當前用戶的標識
          • hasRole,判斷當前用戶是否屬于給定的角色,參數:name
          • hasPermission, 判斷當前用戶是否具有指定的權限,參數:type,action 或者 permission
          • isLoggedIn,判斷當前用戶是否已經登錄
          • hasAnyRole,判斷當前用戶是否屬于給定的某個角色,參數:in

          更多的 Tag 請參考 Shiro Plugin 的 gapi 的文檔。

          如果您已經非常了解了 Shiro,可以采用示例一的方式自己寫所有的代碼,但是對于初學者,作者還建議使用 Shiro plugin,這個插件幫助我們生成了安全相關的基本內容,以及提供了方便的 Tag。

          總結

          讀到這里,是不是覺得 Shiro 真的不錯?!

          這里給大家舉的示例只是拋磚引玉。Shiro 真正的精髓還需要在項目中慢慢的體會。本文是引領我們走向 Shiro 的第一步。在這里要感謝胡鍵對本文編寫的大力支持。

          源代碼中,shiroApp 是示例一的源代碼,ShiroPlugin 是示例二的源代碼。

          為一枚Java程序員,需要掌握哪些技術和工具才能完成一個JavaWeb項目呢?今天羅列一些常用技術和工具,這些技術都是我這10年工作中用的比較多的,我知道技術棧遠不止這些,本人只列自己熟悉和用的最多的,完成一個項目絕對夠用了。說這么多技術不是讓大家都要熟悉,有些太老的現在也用的少了甚至不用了,本人主要結合我這10年開發經驗告訴大家JavaWeb的常用技術棧。

          下面這張是技術棧思維導圖:

          技術棧

          什么是技術棧? 舉個例子: 開發一個普通管理系統,會用到Sprin Boot+MyBatis+Spring+Mysql+Redis+RabbitMq+Nginx+Vue+Shiro+html+等等,這些技術合起來就可以稱為技術棧。

          我將技術棧大致分為5大塊:前端、后端、中間件、數據庫和工具。

          前端

          JSP

          JSP全稱Java Server Pages,是一種動態網頁開發技術。它使用JSP標簽在HTML網頁中插入Java代碼。

          JSP本質上是一個servlet,主要用于實現Java web應用程序的用戶界面部分。

          <html>
              <head>
                     <title>第一個 JSP 程序</title>
              </head>
              <body>
                     <%
                            out.println("Hello World!");
                     %>
              </body>
          </html>

          JSP這種網頁技術我猜5年以下的程序員基本沒接觸過,10年前我接觸的項目前端基本都是采用的JSP技術,jsp配合各種html+jquery/JavaScript+css完成前端頁面開發。

          前端框架

          DWZ、EasyUI、EXT、BootStrap、KendoUI 都是基于基于 HTML、CSS、JavaScript/jquery的一些富文本客戶端UI框架,在當時簡直是后端開發人員的福音。這些框架最大的特點就是官網上提供了各種組件的使用方法,后端人員只要套到JSP頁面中,進行數據渲染即可。這些UI框架風格基本已經固定,更適合開發一些管理類系統,都包括:強大的數據源,通用的拖拉(Drag-and-Drop)功能,模板,和UI控件。

          DWZ

          是中國人自己開發的基于jQuery實現的Ajax RIA開源框架,設計目標是簡單實用,快速開發,降低ajax開發成本。

          官網:https://jui.org/

          EasyUI

          easyui是一種基于jQuery的用戶界面插件集合,為創建現代化,互動,JavaScript應用程序,提供必要的功能。使用easyui你不需要寫很多代碼,你只需要通過編寫一些簡單HTML標記,就可以定義用戶界面,為網頁開發的時間和規模。

          官網;http://www.jeasyui.com/

          EXT

          ExtJS是基于YUI(雅虎用戶界面)的sencha的JavaScript框架和產品,它基本上是具有現代UI的桌面應用程序開發平臺。

          中文官網:http://extjs-doc-cn.github.io/ext4api/#!/api/Ext

          BootStrap

          bootstrap是Twitter推出的一個用于前端開發的開源工具包

          中文官網:https://www.bootcss.com/

          KendoUI

          是一套 JavaScript 函式庫,提供抽象化、可自訂主題的 GUI 控制項與動畫效果。基于 jQuery JavaScript 函式庫,可用來建構互動式的 Web 應用

          官網:http://www.kendoui.io/

          FreeMarker

          FreeMarker是一個免費的模板引擎,一個基于模板生成文本輸出的通用工具,使用純Java編寫的,用來生成HTML Web頁面,特別是基于MVC模式的應用程序。通常由Java程序準備要顯示的數據,由FreeMarker生成頁面,通過模板顯示準備的數據(如下圖)

          FreeMarker不是一個Web應用框架,FreeMarker與容器無關,也可以在模板中使用JSP標記庫。

          <html>
          <head>
            <title>Welcome!</title>
          </head>
          <body>
            <h1>Welcome ${user}!</h1>
            <p>Our latest product:
            <a href="${latestProduct.url}">${latestProduct.name}</a>!
          </body>
          </html>

          html

          上面很多前端框架都是基于html的,需要你有js/jq、css基礎,這是所有前端框架的基礎。因為光框架有時并不能滿足我們的需求,有時需要對框架無法實現的功能需要在框架基礎上調整;還有這個飛速發展的互聯網時代,對前端的要求越來越高,原生html得到了快速發展,基本所有前端效果使用原生時可以實現的。

          VUE

          vue.js 使用了基于 HTML 的模板語法,允許開發者聲明式地將 DOM 綁定至底層 Vue 實例的數據。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循規范的瀏覽器和 HTML 解析器解析。

          在底層的實現上,Vue 將模板編譯成虛擬 DOM 渲染函數。結合響應系統,Vue 能夠智能地計算出最少需要重新渲染多少組件,并把 DOM 操作次數減到最少。

          VUE+elementUI目前使用最多的,尤其是開發一些后臺管理系統還是比較簡單便捷的。

          后端

          servlet

          servlet是Server Applet的簡稱,翻譯過來就是服務程序,簡單的講就是是運行在服務器上的一個小程序,用來處理服務器請求的。我們通過瀏覽器訪問一個應用,在這個過程中,我們的瀏覽器發送訪問請求,服務器接收請求,并對瀏覽器的請求作出相應的處理,這就是我們熟悉的B/S模型(瀏覽器-服務器模型).而servlet就是對請求作出處理的組件,運行于支持Java的應用服務器中。如圖如是:

          struts

          struts主要是指struts1和struts2,是經典的MVC框架,除去一些老項目,現在用的越來越少了。但struts1和struts2還是有區別的,主要區別二者本質不一樣。

          struts1:通過采用Java Servlet/JSP技術,實現了基于Java EE Web應用的Model-View-Controller(MVC)設計模式的應用框架,是MVC經典設計模式中的一個經典產品。

          struts2:以WebWork為核心,采用攔截器的機制來處理用戶的請求,這樣的設計也使得業務邏輯控制器能夠與ServletAPI完全脫離開,所以Struts 2可以理解為WebWork的更新產品。

          最經典的組合strutsMVC+SPring+Hibernate,號稱SSH,當年都是面試必問的技術。

          Spring

          Spring框架是一個開源Java應用框架,解決了開發者在開發中遇到的許多常見的問題,提供了功能強大IOC、AOP及Web MVC等功能。Spring可以單獨應用于應用程序,也可以和Struts、Webwork等眾多Web框架組合使用。Spring框架主要由七部分組成,分別是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。

          持久層框架

          jdbc

          JDBC(Java Data Base Connectivity,java數據庫連接)是一種用于執行SQL語句的Java API,可以為多種關系數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準,據此可以構建更高級的工具和接口,使數據庫開發人員能夠編寫數據庫應用程序。

          早期項目大部分都是通過對JDBC封裝來操作數據庫,實現增刪改查,對性能考慮也不多,隨時間推移不斷衍生出很多框架,例如:mybatis,hibernate等。

          ibatis

          iBATIS一詞來源于“internet”和“abatis”的組合,是一個由Clinton Begin在2001年發起的開放源代碼項目。最初側重于密碼軟件的開發,現在是一個基于Java的持久層框架。iBATIS提供的持久層框架包括SQL Maps和Data Access Objects(DAO),同時還提供一個利用這個框架開發的JPetStore實例。

          iBATIS 目前提供了三種語言實現的版本,包括:Java、.NET以及Ruby。

          mybatis

          MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,并且改名為MyBatis 。

          MyBatis 是一款優秀的持久層框架,它支持定制化SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。

          MyBatis-Plus

          Mybatis 增強工具包 - 只做增強不做改變,簡化CRUD操作

          JPA

          JPA是Java Persistence API的簡稱,中文名Java持久層API,是JDK 5.0注解或XML描述對象-關系表的映射關系,并將運行期的實體對象持久化到數據庫中。

          Sun引入新的JPA ORM規范出于兩個原因:其一,簡化現有Java EE和Java SE應用開發工作;其二,Sun希望整合ORM技術,實現天下歸一。

          Spring Boot

          SpringBoot是由Pivotal團隊在2013年開始研發、2014年4月發布第一個版本的全新開源的輕量級框架。它基于Spring4.0設計,不僅繼承了Spring框架原有的優秀特性,而且還通過簡化配置來進一步簡化了Spring應用的整個搭建和開發過程。另外SpringBoot通過集成大量的框架使得依賴包的版本沖突,以及引用的不穩定性等問題得到了很好的解決。

          分布式/微服務

          Spring Cloud

          Spring Cloud 為開發者提供了在分布式系統(如配置管理、服務發現、斷路器、智能路由、微代理、控制總線、一次性 Token、全局鎖、決策競選、分布式會話和集群狀態)操作的開發工具。使用 Spring Cloud 開發者可以快速實現上述這些模式。

          Spring Cloud 的 GitHub 主頁:https://github.com/spring-cloud

          dubbo

          Dubbo 是阿里巴巴公司開源的一個高性能優秀的服務框架,使得應用可通過高性能的 RPC 實現服務的輸出和輸入功能,可以和 Spring 框架無縫集成。

          主要核心部件:

          Remoting: 網絡通信框架,實現了 sync-over-async 和 request-response 消息機制

          RPC: 一個遠程過程調用的抽象,支持負載均衡、容災和集群功能

          Registry: 服務目錄框架用于服務的注冊和服務事件發布和訂閱

          Spring Cloud Alibaba

          Spring Cloud Alibaba 致力于提供分布式應用服務開發的一站式解決方案。此項目包含開發分布式應用服務的必需組件,方便開發者通過 Spring Cloud 編程模型輕松使用這些組件來開發分布式應用服務。

          依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以將 Spring Cloud 應用接入阿里分布式應用解決方案,通過阿里中間件來迅速搭建分布式應用系統。

          安全框架

          shiro

          Apache Shiro 是 Java 的一個安全框架。目前,使用 Apache Shiro 的人越來越多,因為它相當簡單,對比 Spring Security,可能沒有 Spring Security 做的功能強大,但是在實際工作時可能并不需要那么復雜的東西,所以使用小而簡單的 Shiro 就足夠了。對于它倆到底哪個好,這個不必糾結,能更簡單的解決項目問題就好了。

          Spring Security

          Spring Security是一個能夠為基于Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。

          oauth2.0

          OAuth(開放授權)是一個開放標準,允許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源(如照片,視頻,聯系人列表),而無需將用戶名和密碼提供給第三方應用。

          OAuth 2.0 是目前比較流行的做法,它率先被Google, Yahoo, Microsoft, Facebook等使用。之所以標注為 2.0,是因為最初有一個1.0協議,但這個1.0協議被弄得太復雜,易用性差,所以沒有得到普及。2.0是一個新的設計,協議簡單清晰,但它并不兼容1.0,可以說與1.0沒什么關系。

          項目管理

          maven

          Maven 是 Apache 下的一個純 Java 開發的開源項目。利用一個中央信息片斷能管理一個項目的構建、報告和文檔等步驟。是一個項目管理工具,可以對 Java 項目進行構建、依賴管理。

          ant

          ant 是一個將軟件編譯、測試、部署等步驟聯系在一起加以自動化的一個工具,大多用于Java環境中的軟件開發。在實際軟件開發中,有很多地方可以用到ant。

          gradle

          Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化構建開源工具。它使用一種基于Groovy的特定領域語言(DSL)來聲明項目設置,目前也增加了基于Kotlin語言的kotlin-based DSL,拋棄了基于XML的各種繁瑣配置。

          服務器軟件

          tomcat

          Tomcat 服務器是一個免費的開放源代碼的Web 應用服務器,屬于輕量級應用服務器,在中小型系統和并發訪問用戶不是很多的場合下被普遍使用,是開發和調試JSP 程序的首選

          Apache

          Apache(阿帕奇)是世界使用排名第一的Web服務器軟件。它可以運行在幾乎所有廣泛使用的計算機平臺上,由于其跨平臺和安全性被廣泛使用,是最流行的Web服務器端軟件之一

          Jetty

          Jetty 是一個開源的servlet容器,它為基于Java的web容器,例如JSP和servlet提供運行環境。

          weblogic

          WebLogic Server是專門為企業電子商務應用系統開發的。企業電子商務應用系統需要快速開發,并要求服務器端組件具有良好的靈活性和安全性,同時還要支持關鍵任務所必需的擴展、性能、和高可用性。WebLogic Server簡化了可移植及可擴展的應用系統的開發,并為其它應用 系統和系統提供了豐富的互操作性。

          nginx

          Nginx是一款輕量級的Web服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器,在BSD-like 協議下發行。其特點是占有內存少,并發能力強。

          中間件

          緩存

          緩存是現在系統中必不可少的模塊,并且已經成為了高并發高性能架構的一個關鍵組件。緩存的主要作用:提升性能緩解數據庫壓力

          Redis

          Redis是一個開源的內存數據結構存儲,用作數據庫、緩存和消息代理。提供諸如字符串、哈希、列表、集合、帶范圍查詢的排序集合、位圖、超日志、地理空間索引和流等數據結構。具有內置的復制、Lua腳本、LRU逐出、事務和不同級別的磁盤持久性,并通過Redis Sentinel和Redis Cluster的自動分區提供高可用性。

          MongoDB

          MongoDB 是一個基于分布式文件存儲的數據庫。由 C++ 語言編寫。旨在為 WEB 應用提供可擴展的高性能數據存儲解決方案。是一個介于關系數據庫和非關系數據庫之間的產品,是非關系數據庫當中功能最豐富,最像關系數據庫的。

          Memcached

          Memcached是一個自由開源的,高性能,分布式內存對象緩存系統,用來提高Web應用擴展性的重要因素。是一個基于內存的key-value存儲,用來存儲小塊的任意數據(字符串、對象)。簡潔而強大,它的簡潔設計便于快速開發,減輕開發難度,解決了大數據量緩存的很多問題。一般的使用目的是,通過緩存數據庫查詢結果,減少數據庫訪問次數,以提高動態Web應用的速度、提高可擴展性。

          差異性我就不多說了,簡單說下他們的使用場景:

          • Memcached:動態系統中減輕數據庫負載,提升性能;做緩存,適合多讀少寫,大數據量的情況(如人人網大量查詢用戶信息、好友信息、文章信息等)。
          • Redis:適用于對讀寫效率要求都很高,數據處理業務復雜和對安全性要求較高的系統(如新浪微博的計數和微博發布部分系統,對數據安全性、讀寫要求都很高)。
          • MongoDB:主要解決海量數據的訪問效率問題。

          搜索

          solr

          Solr是一個獨立的企業級搜索應用服務器,它對外提供類似于Web-service的API接口。用戶可以通過http請求,向搜索引擎服務器提交一定格式的XML文件,生成索引;也可以通過Http Get操作提出查找請求,并得到XML格式的返回結果。

          Elasticsearch

          Elasticsearch是一個基于Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基于RESTful web接口

          二者主要區別

          es基本是開箱即用,非常簡單,Solr略微復雜。

          Solr 支持更多格式的數據,比如JSON、XML、CSV,而 Elasticsearch 僅支持json文件格式。

          Solr 查詢快,但更新索引時慢(即插入刪除慢),ES建立索引快(即查詢慢),即實時性查詢快。

          ELK

          之所以推薦ELK是因為面對分布式微服務情況下,會顯示出他的威力,不管是數據收集、數據處理、還是數據分析可以節約很多時間。ELK是Elasticsearch + Logstash + Kibana三個開源軟件的組合,但是通常為了提高性能需要借助kafka,利用Filebeat進行日志收集,下面這個架構圖是我做過的一個日志服務平臺。

          定時任務

          說定定時任務大家可能都接觸過,例如Spring自帶的定時任務SpringTask,但是SpringTask是存在很多問題的,例如:最致命的一個問題就是一旦定時拋出異常,生命就結束,下一次不會再執行。復雜業務中使用起來是不方便的,這里推薦兩個定時任務框架Quartz和xx-job,第三方的功能比較強大,好用。

          Quartz

          Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,完全由Java開發,可以用來執行定時任務,類似于java.util.Timer。但是相較于Timer, Quartz增加了很多功能:

          • 持久性作業 - 就是保持調度定時的狀態;
          • 作業管理 - 對調度作業進行有效的管理;

          xx-job

          XXL-JOB是一個輕量級分布式任務調度平臺,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼并接入多家公司線上產品線,開箱即用。

          目前已有多家公司接入xxl-job,包括比較知名的大眾點評,京東,優信二手車,北京尚德,360金融 (360),聯想集團 (聯想),易信 (網易)等等.... Quartz作為開源作業調度中的佼佼者,是作業調度的首選

          Quartz在集群環境下只能通過API的方式對任務管理,同時,系統侵入性相當嚴重,而XX-JOB可以完美解決集群下任務額管理。所以,可以根據自己業務情況選擇合適定時任務框架,

          配置中心

          什么是配置中心?

          集中將應用系統中對配置信息的管理作為一個新的應用功能模塊,區別與傳統的配置信息分散到系統各個角落方式,進行集中統一管理,并且提供額外功能。尤其是在微服務架構中,是不可或缺組件,甚至是必要組件之一。

          為什么要使用配置中心?

          在微服務體系中,服務的數量以及配置信息的日益增多,比如各種服務器參數配置、各種數據庫訪問參數配置、各種環境下應用配置信息的不同、配置信息修改之后實時生效等等,傳統的配置文件方式或者將配置信息存放于數據庫中的方式已無法滿足開發人員對配置管理的要求。常見的配置中心中間件有:SpringCloud Config ,Nacos,apollo等。

          SpringCloud Config

          2014年9月開源,Spring Cloud 生態組件,可以和Spring Cloud體系無縫整合,Spring Cloud Config支持通過/bus/refresh端點的destination參數來指定要更新配置的機器,不過整個流程不夠自動化和體系化。相對于Apollo和Nacos還是比較弱的。

          Nacos

          2018年6月,阿里開源的配置中心,也可以做DNS和RPC的服務發現。Nacos使用起來相對比較簡潔,在對性能要求比較高的大規模場景更適合。此外,Nacos除了提供配置中心的功能,還提供了動態服務發現、服務共享與管理的功能,降低了服務化改造過程中的難度。

          apollo(阿波羅)

          2016年5月,攜程開源的配置管理中心,具備規范的權限、流程治理等特性,Apollo可以直接在控制臺上點灰度發布指定發布機器的IP,接著再全量發布,做得比較體系化。

          三者對比如何選擇:

          核心功能: Apollo和Nacos相對于Spring Cloud Config的生態支持更廣

          實時推送: Nacos和Apollo在配置實時推送鏈路上是比較簡單高效的,Spring Cloud Config比較復雜。

          高可用部署: Nacos的部署結構比較簡單,運維成本較低。Apollo部署組件較多,運維成本比Nacos高。Spring Cloud Config生產高可用的成本最高。

          監控

          服務器監控是實時掌握服務器工作狀態,并在需要時可以隨時調用監控記錄進行查看。

          SpringBootAdmin

          Spring Boot Admin用來管理和監控Spring Boot應用程序,通過UI來查看應用程序的狀態,例如Spring Beans,系統屬性,線程,http的調用情況等有限狀態。

          Druid

          我知道Druid更多的用途就是連接池,其實他還有一個對SQL監控功能。

          SkyWalking

          Skywalking是由國內開源愛好者吳晟(原OneAPM工程師,目前在華為)開源并提交到Apache孵化器的產品,它同時吸收了Zipkin/Pinpoint/CAT的設計思路,支持非侵入式埋點。是一款基于分布式跟蹤的應用程序性能監控系統。另外社區還發展出了一個叫OpenTracing的組織,旨在推進調用鏈監控的一些規范和標準工作。

          存儲

          把涉及到數據庫相關或者可以作為數據倉庫的中間件都歸到一起了。

          MyCat

          Mycat是一個開源數據庫中間件,是一個實現了MySQL協議的的數據庫中間件服務器,我們可以把它看作是一個數據庫代理,用MySQL客戶端工具和命令行訪問Mycat,而Mycat再使用用MySQL原生(Native)協議與多個MySQL服務器通信,也可以用JDBC協議與大多數主流數據庫服務器通信,包括SQL Server、Oracle、DB2、PostgreSQL等主流數據庫,也支持MongoDB這種新型NoSQL方式的存儲,未來還會支持更多類型的存儲;一般地,Mycat主要用于代理MySQL數據庫,雖然它也支持去訪問其他類型的數據庫;

          Mycat官網:http://www.mycat.io/

          Canal

          我們先看官網的介紹

          canal,譯意為水道/管道/溝渠,主要用途是基于 MySQL 數據庫增量日志解析,提供增量數據訂閱和消費

          這句介紹有幾個關鍵字:增量日志,增量數據訂閱和消費

          這里我們可以簡單地把canal理解為一個用來同步增量數據的一個工具

          接下來我們看一張官網提供的示意圖:

          sharing-jdbc

          定位為輕量級Java框架,在Java的JDBC層提供的額外服務。 它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解為增強版的JDBC驅動,完全兼容JDBC和各種ORM框架。

          主要功能

          • 分庫 & 分表
          • 讀寫分離
          • 分布式主鍵

          zookeeper

          ZooKeeper是Hadoop的正式子項目,它是一個針對大型分布式系統的可靠協調系統,提供的功能包括:配置維護、名字服務、分布式同步、組服務等。ZooKeeper的目標就是封裝好復雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。

          事務

          這個事務更多指的是分布式事務處理插件。

          Apache ShardingSphere

          Apache ShardingSphere(Incubator) 是一套開源的分布式數據庫中間件解決方案組成的生態圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(規劃中)這3款相互獨立,卻又能夠混合部署配合使用的產品組成。它們均提供標準化的數據分片、分布式事務和數據庫治理功能,可適用于如Java同構、異構語言、容器、云原生等各種多樣化的應用場景。

          Seata

          Seata 是 Simple Extensible Autonomous Transaction Architecture 的簡寫,由 feascar 改名而來。是阿里開源的分布式事務框架,屬于二階段提交模式。

          消息隊列

          什么是消息隊列

          消息隊列是一個存放消息的容器,當我們需要使用消息的時候可以取出消息供自己使用。消息隊列是分布式系統中重要的組件,使用消息隊列主要是為了通過異步處理提高系統性能和削峰、降低系統耦合性。目前使用較多的消息隊列有ActiveMQ,RabbitMQ,Kafka,RocketMQ。

          為什么需要消息隊列

          1.通過異步處理提高系統性能(削峰、減少響應所需時間);

          2.降低系統耦合性;

          Kafka

          Kafka是由Apache軟件基金會開發的一個開源流處理平臺,由Scala和Java編寫。Kafka是一種高吞吐量的分布式發布訂閱消息系統,它可以處理消費者在網站中的所有動作流數據。這些數據通常是由于吞吐量的要求而通過處理日志和日志聚合來解決。 對于像Hadoop一樣的日志數據和離線分析系統,但又要求實時處理的限制,這是一個可行的解決方案。Kafka的目的是通過Hadoop的并行加載機制來統一線上和離線的消息處理,也是為了通過集群來提供實時的消息。

          RabbitMQ

          AMQP,即Advanced Message Queuing Protocol,高級消息隊列協議,是應用層協議的一個開放標準,為面向消息的中間件設計。消息中間件主要用于組件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。 AMQP的主要特征是面向消息、隊列、路由(包括點對點和發布/訂閱)、可靠性、安全。 RabbitMQ是一個開源的AMQP實現,服務器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。

          ActiveMQ

          ActiveMQ是一種開源的基于JMS(Java Message Servie)規范的一種消息中間件的實現,ActiveMQ的設計目標是提供標準的,面向消息的,能夠跨越多語言和多系統的應用集成消息通信中間件。

          三者區別及其使用場景

          特性 ActiveMQ RabbitMQ kafka 開發語言 java erlang scala 單機吞吐量 萬級 萬級 10萬級 時效性 ms級 us級 ms級以內 可用性 高(主從架構) 高(主從架構) 非常高(分布式架構) 功能特性 成熟的產品,在很多公司得到應用;有較多的文檔;各種協議支持較好 基于erlang開發,所以并發能力很強,性能極其好,延時很低;管理界面較豐富 只支持主要的MQ功能,像一些消息查詢,消息回溯等功能沒有提供,畢竟是為大數據準備的,在大數據領域應用廣。

          數據庫

          該數據庫主要是指關系型數據庫,是按照數據結構來組織、存儲和管理數據的倉庫,數據庫是存放數據的倉庫,是一個系統或者軟件必不可少的一部分。每個數據庫都有一個或多個不同的 API 用于創建,訪問,管理,搜索和復制所保存的數據。我們也可以將數據存儲在文件中,但是在文件中讀寫數據速度相對較慢。

          所以,現在我們使用關系型數據庫管理系統來存儲和管理大數據量。所謂的關系型數據庫,是建立在關系模型基礎上的數據庫,借助于集合代數等數學概念和方法來處理數據庫中的數據。

          關系數據庫管理系統的特點:

          • 1.數據以表格的形式出現
          • 2.每行為各種記錄名稱
          • 3.每列為記錄名稱所對應的數據域
          • 4.許多的行和列組成一張表單
          • 5.若干的表單組成database

          常見的數據管理系統主要有:oracle、mysql、SQL Server、access、TiDB。

          oracle

          Oracle Database,簡稱 Oracle。Oracle 數據庫系統是美國 Oracle 公司(甲骨文)提供的以分布式數據庫為核心的一組軟件產品,是目前最流行的客戶/服務器(client/server)的數據庫之一。Oracle 數據庫是目前世界上使用最為廣泛的數據庫管理系統,作為一個通用的數據庫系統,它具有完整的數據管理功能;作為一個關系型數據庫,它是一個完備關系的產品;作為分布式數據庫它實現了分布式處理功能,但它的所有知識,只要在一種機型上學習了Oracle知識,便能在各種類型的機器上使用它。

          mysql

          MySQL 是最流行的關系型數據庫管理系統,在 WEB 應用方面 MySQL 是最好的 RDBMS(Relational Database Management System:關系數據庫管理系統)應用軟件之一。目前也是Oracle 公司來托管。

          SQL Server

          美國Microsoft公司推出的一種關系型數據庫系統。SQL Server是一個可擴展的、高性能的、為分布式客戶機/服務器計算所設計的數據庫管理系統,實現了與WindowsNT的有機結合,提供了基于事務的企業級信息管理系統方案。

          access

          Access是微軟把數據庫引擎的圖形用戶界面和軟件開發工具結合在一起的一個數據庫管理系統。它是微軟OFFICE的一個成員, 在包括專業版和更高版本的office版本里面被單獨出售。

          TiDB

          TiDB 是 PingCAP 公司自主設計、研發的開源分布式關系型數據庫,是一款同時支持在線事務處理與在線分析處理 (Hybrid Transactional and Analytical Processing, HTAP)的融合型分布式數據庫產品,具備水平擴容或者縮容、金融級高可用、實時 HTAP、云原生的分布式數據庫、兼容 MySQL 5.7 協議和 MySQL 生態等重要特性。目標是為用戶提供一站式 OLTP (Online Transactional Processing)、OLAP (Online Analytical Processing)、HTAP 解決方案。TiDB 適合高可用、強一致要求較高、數據規模較大等各種應用場景。

          上面這幾個數據庫優缺點都比較明顯,不在啰嗦了,大家在工作中可以根據自己實際情況選擇合適的數據。

          工具

          開發

          IntelliJ IDEA

          IntelliJ在業界被公認為最好的java開發工具,尤其在智能代碼助手、代碼自動提示、重構、JavaEE支持、各類版本工具(git、svn等)、JUnit、CVS整合、代碼分析、 創新的GUI設計等方面的功能可以說是超常的。IDEA是JetBrains公司的產品,這家公司總部位于捷克共和國的首都布拉格,開發人員以嚴謹著稱的東歐程序員為主。它的旗艦版本還支持HTML,CSS,PHP,MySQL,Python等。免費版只支持Java,Kotlin等少數語言。

          eclipse

          Eclipse 是一個開放源代碼的、基于 Java 的可擴展開發平臺, 是 Java 的集成開發環境(IDE),當然 Eclipse 也可以作為其他開發語言的集成開發環境,如C,C++,PHP,和 Ruby 等。

          MyEclipse

          MyEclipse,是在Eclipse 基礎上加上自己的插件開發而成的功能強大的企業級集成開發環境,主要用于Java、Java EE以及移動應用的開發。在最新版本的MyEclipse中,配合CodeMix使用支持也十分廣泛,尤其是對各種開源產品和主流開發框架的支持相當不錯。目前已支持PHP、Python、Vue、Angular、React、Java、Java EE等語言和框架開發。

          這三款工具好壞我也不做任何評價,每個工具用戶都不少,我周圍IntelliJ IDEA和MyEclipse都有,我個人比較喜歡用IntelliJ IDEA。

          客戶端工具

          版本控制

          常見的版本空間工具svn和git

          svn

          TortoiseSVN 是 Subversion 版本控制系統的一個免費開源客戶端,可以超越時間的管理文件和目錄。文件保存在中央版本庫,除了能記住文件和目錄的每次修改以外,版本庫非常像普通的文件服務器。你可以將文件恢復到過去的版本,并且可以通過檢查歷史知道數據做了哪些修改,誰做的修改。這就是為什么許多人將 Subversion 和版本控制系統看作一種“時間機器”。

          git

          Git 是用于Linux內核開發的版本控制工具。與常用的版本控制工具 Subversion 不同,它采用了分布式版本庫的方式,不必服務器端軟件支持,代碼的發布和交流極其方便。 Git 的速度很快,這樣的大項目來說自然很重要。 Git 最為出色的是它的合并跟蹤(merge tracing)能力。

          SVN的特點是簡單,只是需要一個放代碼的地方時用是OK的。

          Git的特點版本控制可以不依賴網絡做任何事情,對分支和合并有更好的支持(這應該算是開發者最關心的地方)。

          數據庫

          Navicat

          Navicat是一套快速、可靠并價格相當便宜的數據庫管理工具,專為簡化數據庫的管理及降低系統管理成本而設。它的設計符合數據庫管理員、開發人員及中小企業的需要。Navicat 是以直覺化的圖形用戶界面而建的,讓你可以以安全并且簡單的方式創建、組織、訪問并共用信息。

          PLSQL

          PL/SQL Developer是一個集成開發環境,專門開發面向Oracle數據庫的應用。PL/SQL也是一種程序語言,叫做過程化SQL語言(Procedural Language/SQL)。PL/SQL是Oracle數據庫對SQL語句的擴展。在普通SQL語句的使用上增加了編程語言的特點,所以PL/SQL把數據操作和查詢語句組織在PL/SQL代碼的過程性單元中,通過邏輯判斷、循環等操作實現復雜的功能或者計算,PL/SQL 只有 Oracle 數據庫有

          Redis Desktop Manager

          Redis Desktop Manager是一款windows平臺下的可視化redis數據庫桌面管理工具,使用它你可以查看、刪除、修改你的redis數據庫數據!

          linux遠程

          XShell

          XShell是一個強大的安全終端模擬軟件,它支持SSH1,SSH2,以及Microsoft Windows平臺的TELNET協議。 XShell可以在Windows界面下用來訪問遠端不同系統下的服務器,從而比較好的達到遠程控制終端的目的。

          WinSCP

          寶塔

          寶塔面板是一個可以安裝在服務器上的集成環境,并配套了web管理面板,可以在瀏覽器上直接控制你的服務器,非常方便。 可以一鍵創建網站、FTP、數據庫、SSL;安全管理,計劃任務,文件管理,PHP多版本共存及切換;自帶基礎網站環境,支持windows系統(apache)和linux系統(apache或nginx)。

          SecureCRT

          Secure CRT 是一款SSH客戶端軟件,通過使用內含的VCP命令行程序可以進行加密文件的傳輸。

          postMan

          Postman一款非常流行的API調試工具。其實,開發人員用的更多。因為測試人員做接口測試會有更多選擇,例如Jmeter、soapUI等。不過,對于開發過程中去調試接口,Postman確實足夠的簡單方便,而且功能強大。

          輔助

          Typora+PicGo

          Typora+PicGo,最好用的Markdown+最好用的圖床工具!如果寫博客的可以收藏起來。

          notepad++

          Notepad++中文版是程序員必備的文本編輯器,Notepad++中文版小巧高效,支持27種編程語言,通吃C,C++ ,Java ,C#, XML, HTML, PHP,JS 等,Notepad++中文版編輯器可完美地取代微軟的記事本。

          畫圖

          visio

          Office Visio 是Office軟件系列中的負責繪制流程圖和示意圖的軟件,是一款便于IT和商務人員就復雜信息、系統和流程進行可視化處理、分析和交流的軟件。使用具有專業外觀的 Office Visio 圖表,可以促進對系統和流程的了解,深入了解復雜信息并利用這些知識做出更好的業務決策。常見軟件架構、流程圖都可以在里面完成。

          processon

          ProcessOn是一個在線作圖工具的聚合平臺, 它可以在線畫流程圖、思維導圖、UI原型圖、UML、網絡拓撲圖、組織結構圖等等, 您無需擔心下載和更新的問題,不管Mac還是Windows,一個瀏覽器就可以隨時隨地的發揮創意,規劃工作。

          官網:https://www.processon.com/

          PowerDesigner

          owerDesigner是一款非常全面的數據庫設計工具。使用PowerDesigner可以快速創建表,支持表與表之間建立關系,界面簡潔,功能強大。同時支持將sql腳本導出,多種導出類型任意挑選,簡單實用。

          Xmind

          XMind 是一個全功能的思維導圖和頭腦風暴軟件,為激發靈感和創意而生。作為一款有效提升工作和生活效率的生產力工具,受到全球百千萬用戶的青睞。

          iReport

          說到 iReport 不得不先介紹 Jasperreport,Jasperreport 是一個報表制作程序,用戶需要按照它制定的規則編寫一個 XML 文件,然后得到用戶需要輸出的格式文件。它支持輸出的文件格式包括 PDF,HTML,XML,XLS,CVS 等等。而 iReport 就是一個制作 Jasperreport 的 XML 文件的可視化開發工具。

          瀏覽器

          Chrome

          Google Chrome是一款由Google公司開發的網頁瀏覽器,該瀏覽器基于其他開源軟件撰寫,包括WebKit,目標是提升穩定性、速度和安全性,并創造出簡單且有效率的使用者界面。

          搜狗

          搜狗瀏覽器 由搜狗公司開發,基于谷歌chromium內核,力求為用戶提供跨終端無縫使用體驗,讓上網更簡單、網頁閱讀更流暢的瀏覽器。

          火狐

          Mozilla Firefox,中文俗稱“火狐”,是一個由Mozilla開發的自由及開放源代碼的網頁瀏覽器。其使用Gecko排版引擎,支持多種操作系統,如Windows、macOS及GNU/Linux等

          IE

          Internet Explorer(簡稱:IE)是微軟公司微軟公司推出的一款網頁瀏覽器。原稱Microsoft Internet Explorer(6版本以前)和Windows Internet Explorer(7、8、9、10、11版本)。在IE7以前,中文直譯為“網絡探路者”,但在IE7以后官方便直接俗稱"IE瀏覽器"。

          如果做前端開發,這幾款瀏覽器兼容性都得兼顧。很早之前IE瀏覽器市場是比較大,隨著時間推移,谷歌瀏覽器占據了比較大的市場。我個人日常開發中谷歌用的比較多,特殊情況才會使用其它瀏覽器。

          性能分析

          jmeter

          JMeter是Apache組織開發的基于Java的壓力測試工具。用于對軟件做壓力測試,它最初被設計用于Web應用測試,但后來擴展到其他測試領域。 它可以用于測試靜態和動態資源,例如靜態文件、Java 服務程序、CGI 腳本、Java 對象、數據庫, 等等。

          ab

          apache bench簡稱ab,它是apache自帶的壓力測試工具。ab非常實用,它不僅可以對apache服務器進行網站訪問壓力測試,也可以對或其它類型的服務器進行壓力測試。

          MAT

          MAT是Java堆內存分析工具,可從http://www.eclipse.org/mat/中下載。

          你在成為大神的路上都學習了哪些技術,歡迎留言交流。


          主站蜘蛛池模板: 欧洲亚洲综合一区二区三区| 射精专区一区二区朝鲜| 一区二区三区日韩| 国产成人免费一区二区三区| 精品视频无码一区二区三区| 亚洲美女高清一区二区三区 | 亚洲日本乱码一区二区在线二产线| 91精品一区二区| 久久高清一区二区三区| 亚洲AV无码一区二区三区国产| 成人免费视频一区二区三区| 国产一区二区三区韩国女主播| 人妻免费一区二区三区最新 | 国产精品自拍一区| 日韩一区二区在线观看视频 | 东京热人妻无码一区二区av| 国产一区二区精品久久| 成人区精品一区二区不卡| 亚洲国产高清在线一区二区三区| 国产成人高清精品一区二区三区| 精品日韩一区二区| 无码精品不卡一区二区三区| 国产精品一区二区久久乐下载 | 国产一区二区三区在线免费观看| 波多野结衣一区二区三区| 日韩三级一区二区三区| 国产精品成人一区二区| 久久人妻无码一区二区| 久久无码一区二区三区少妇| 在线成人一区二区| 日韩一区二区电影| 亚洲欧美日韩国产精品一区| 精品国产免费一区二区三区| 精品欧洲av无码一区二区| 无码一区二区三区亚洲人妻 | 国产一区二区三区不卡在线看| 国产人妖视频一区二区破除| 黄桃AV无码免费一区二区三区| 一区二区三区观看免费中文视频在线播放| bt7086福利一区国产| 78成人精品电影在线播放日韩精品电影一区亚洲 |