開發(fā)環(huán)境必備軟件:
composer-cli
generator-hyperledger-composr
composer-rest-server
Yeoman
安裝playground
1,playground 的Web Browser區(qū)域提供了在頁面定義模型、測試模型的能力。并不保存。但可以導出bna文件
2,connection區(qū)域提供了在開發(fā)環(huán)境布署合約,會生成一個智能合約的docker運行環(huán)境.
3,可以在上圖中上部分的My Business Networks 工作區(qū)點擊虛業(yè)部分Deploy a new business network
4,在接下來頁面中選中一個示例。如 marble neetworkd. 選擇 ID and Secret 填入admin 和 adminpw
5,點擊Deploy按鈕后會發(fā)布一個合約.并跳到測試頁如下圖:
6,在上圖中 Test Tab頁可以進行測試 ,在Define Tab頁可以導出bna文件.
7,在第一幅圖中點擊下載按鈕,會下載一個 .card文件,描述了連接fabric peer節(jié)點等相關(guān)連接信息.記得要導 PeerAdmin@hlfv1的card和你自己測試用的card,及bna文件
8,分別執(zhí)行 composer card import -f PeerAdmin.card ,composer card import -f admin.card .composer card list 可以查看你導入的card的name信息.
9,composer-rest-server -c admin@empty-business-network -n always -w true 啟動rest服務默認端口3000.
10,好了,可以體驗一下fabric是個什么玩意了。:) 88!
一,需求收集,分析。
此處省略2000字。。。 見前篇 《需求收集、分析小結(jié)》http://www.aygfsteel.com/fool/archive/2017/04/28/432489.html
二,概念架構(gòu)/概念模型
從需求中找出關(guān)健、重大需求,進行概念建模.下面三個圖稱之魯棒圖。其中控制對象理解為mvc模式中的控制器和model。使用魯棒圖可以建立概念模型,約等于初步設(shè)計。初步設(shè)計并不關(guān)心細節(jié)。
魯棒圖建立概念模型語法:
概念設(shè)計舉例:
上次談到超市小票如何分析實體對象,本次接著舉例如何對收銀進行概念建模
如上圖:具備基本收銀功能的概念模型。概念模型建模可以是增量的。比如商品折扣或其它
促銷活動等。
概念架構(gòu)的用途:
1) 可以幫助我們找出領(lǐng)域模型中的實體對象。
2) 檢查需求用例是否正確和完善。
3)初步設(shè)計,魯棒圖是一種初步設(shè)計技術(shù)。
4)根據(jù)用例和概念設(shè)計劃分系統(tǒng)、子系統(tǒng)、模塊或者包。借助魯棒圖,初步識別功能背后的職責,規(guī)劃切分系統(tǒng)的方式。
三,關(guān)注非功能性需求,包括運行期質(zhì)量和開發(fā)期質(zhì)量。
運用目標—場景—決策表對非功能性需求作出決策.小舉例:
目標 | 場景 | 決策 |
易用性 | 銷售員需要輸入條碼檢索商品,繁瑣且速度慢 | 根據(jù)條碼,品名模糊匹配檢索商品,提供輔助錄入。 |
性能 | 長時間穩(wěn)定運行 | 數(shù)據(jù)庫集群,服務應用集群 |
四,細化架構(gòu)。RUP 4+1視圖法則將架構(gòu)需要關(guān)注的不同的點使用不同的視圖表示.從不同的維度對系統(tǒng)進行解讀,從而形成統(tǒng)一軟件過程架構(gòu)描述。
運行架構(gòu):
關(guān)心進程、線程、同步的相關(guān)設(shè)計,捕捉并發(fā)和同步特征
邏輯架構(gòu):
關(guān)心邏輯層(layer)的劃分,系統(tǒng)/子系統(tǒng)的劃分,劃分模塊及其接口的定義。功能組劃分也屬于邏輯架構(gòu).功能:不僅包括用戶可見的功能,還包括為實現(xiàn)用戶功能而必須提供的"輔助功能模塊";它們可能是邏輯層、功能模塊等。
物理架構(gòu):
關(guān)心服務器選型,物理層劃分(tier)。 描述如何部署機器和網(wǎng)絡(luò)來配合軟件系統(tǒng)的可靠性、可伸縮性等要求.layer就運行在tier上。Tier反映系統(tǒng)伸縮能力。
開發(fā)架構(gòu):
描述了在開發(fā)環(huán)境中軟件的靜態(tài)組織結(jié)構(gòu)。即開發(fā)工具下的開發(fā)視圖,描述文件編譯及其依賴關(guān)系。而使用maven管理開發(fā)的項目編譯及依賴關(guān)系結(jié)構(gòu)更加分明。
數(shù)據(jù)架構(gòu):
關(guān)心數(shù)據(jù)的存儲、分布和文件的存放及數(shù)據(jù)的復制,傳遞,同步。數(shù)據(jù)的存放包括sql,內(nèi)存數(shù)據(jù)庫,nosql數(shù)據(jù)庫等.
邏輯架構(gòu)設(shè)計舉例:
還是用收銀系統(tǒng)簡單舉例,收銀系統(tǒng)邏輯架構(gòu)圖如下:
整個系統(tǒng)劃系統(tǒng)為系統(tǒng),切為兩個系統(tǒng),一個收銀員角色處理的業(yè)務,收銀系統(tǒng)。
一個后臺管理系統(tǒng)。后臺管理系統(tǒng)包括用戶管理模塊,基礎(chǔ)資料模塊(產(chǎn)品資料等)
銷售模塊(本例對銷售單)。另外,因為收銀系統(tǒng)需要和后臺系統(tǒng)交互,把收銀系統(tǒng)需要使用到的相關(guān)的各模塊封裝成一個接口模塊,專門處理和收銀系統(tǒng)交互的模塊。系統(tǒng)、模塊之間的通訊方式應當盡量避免雙向。相互依賴可能會引發(fā)很多問題。
物理架構(gòu)設(shè)計舉例:
物理架構(gòu)和邏輯架構(gòu)可以相互印證。描述軟件系統(tǒng)的物理布署。
如果考慮運行期質(zhì)量比如長時間運行布署圖可能應用做集群。數(shù)據(jù)庫做集群等。邏輯層layer運行在物理層tier之上
運行架構(gòu)和數(shù)據(jù)架構(gòu)視圖根據(jù)實際情況可選設(shè)計
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<!-- 自己寫一個認證提供者類 我加的-->
<ref local="activeDirectoryProvider" />
<ref local="daoAuthenticationProvider" />
<ref local="anonymousAuthenticationProvider" />
<ref local="rememberMeAuthenticationProvider" />
</list>
</property>
</bean>
<!-- 認證提供者類的配置 我加的-->
<bean id="activeDirectoryProvider"
class="net.omw.utility.AcegiTestProvider">
<property name="url" value="ldap://172.108.4.2"> </property>
<property name="port" value="389"> </property>
<!--domain取值域服務器的配置-->
<property name="domain" value="SUNTECH"> </property>
<!-- <property name="sessionController" ref="concurrentSessionController"></property> -->
</bean>
<bean id="jdbcDaoImpl"
class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource">
<ref bean="coreDataSource" />
</property>
<property name="usersByUsernameQuery">
<value>
select C_OPER_ID,C_PASSWORD,1 from Operator where
C_OPER_ID = ? and C_STATUS='Y'
</value>
</property>
<property name="authoritiesByUsernameQuery">
<value>
select C_OPER_ID,C_PASSWORD,1 from Operator where
C_OPER_ID = ? and C_STATUS='Y'
</value>
</property>
</bean>
<bean id="passwordEncoder"
class="org.acegisecurity.providers.encoding.Md5PasswordEncoder">
<property name="encodeHashAsBase64" value="false"></property>
</bean>
<bean id="daoAuthenticationProvider"
class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<ref local="jdbcDaoImpl" />
</property>
<!-- <property name="userCache">
<ref local="userCache" />
</property>-->
<property name="passwordEncoder">
<ref local="passwordEncoder" />
</property>
</bean>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
<bean id="userCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager" />
</property>
<property name="cacheName">
<value>userCache</value>
</property>
</bean>
<bean id="userCache"
class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
<property name="cache">
<ref local="userCacheBackend" />
</property>
</bean>
<bean id="loggerListener"
class="org.acegisecurity.event.authentication.LoggerListener" />
<bean id="anonymousProcessingFilter"
class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
<property name="key">
<value>foobar</value>
</property>
<property name="userAttribute">
<value>anonymousUser,ROLE_ANONYMOUS</value>
</property>
</bean>
<bean id="anonymousAuthenticationProvider"
class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="key">
<value>foobar</value>
</property>
</bean>
<bean id="httpSessionContextIntegrationFilter"
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
</bean>
<bean id="rememberMeProcessingFilter"
class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager">
<ref local="authenticationManager" />
</property>
<property name="rememberMeServices">
<ref local="rememberMeServices" />
</property>
</bean>
<bean id="rememberMeServices"
class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService">
<ref local="jdbcDaoImpl" />
</property>
<property name="key">
<value>springRocks</value>
</property>
</bean>
<bean id="rememberMeAuthenticationProvider"
class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key">
<value>springRocks</value>
</property>
</bean>
<bean id="logoutFilter"
class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/login/loginPage.jsp" />
<constructor-arg>
<list>
<ref bean="rememberMeServices" />
<bean
class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
</list>
</constructor-arg>
</bean>
<bean id="securityContextHolderAwareRequestFilter"
class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />
<bean id="exceptionTranslationFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<ref local="authenticationProcessingFilterEntryPoint" />
</property>
<property name="accessDeniedHandler">
<bean
class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage"
value="/common/AccessDenied.jsp" />
</bean>
</property>
</bean>
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager">
<ref bean="authenticationManager" />
</property>
<property name="authenticationFailureUrl">
<value>/login/Login.action?login_msg=1</value>
</property>
<property name="defaultTargetUrl">
<value>/login/Login.action?login_msg=0</value>
</property>
<property name="filterProcessesUrl">
<value>/j_acegi_security_check</value>
</property>
<property name="rememberMeServices">
<ref local="rememberMeServices" />
</property>
</bean>
<bean id="authenticationProcessingFilterEntryPoint"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl">
<value>/login/loginPage.jsp</value>
</property>
<property name="forceHttps">
<value>false</value>
</property>
<property name="serverSideRedirect" value="false"></property>
</bean>
<bean id="httpRequestAccessDecisionManager"
class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions">
<value>false</value>
</property>
<property name="decisionVoters">
<list>
<ref bean="roleVoter" />
</list>
</property>
</bean>
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter" />
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="validateConfigAttributes" value="true" />
<property name="authenticationManager">
<ref bean="authenticationManager" />
</property>
<property name="accessDecisionManager">
<ref local="httpRequestAccessDecisionManager" />
</property>
<property name="objectDefinitionSource"
ref="rdbmsFilterInvocationDefinitionSource" />
</bean>
<bean id="rdbmsFilterInvocationDefinitionSource"
class="net.omw.utility.acegi.interceptor.RdbmsFilterInvocationDefinitionSource">
<property name="dataSource">
<ref bean="coreDataSource" />
</property>
<property name="webresdbCache" ref="webresCacheBackend" />
</bean>
<bean id="webresCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager" />
</property>
<property name="cacheName">
<value>webresdbCache</value>
</property>
</bean>
<!--
<bean id="switchUserProcessingFilter" class="org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter">
<property name="userDetailsService" ref="jdbcDaoImpl" />
<property name="switchUserUrl"><value>/j_acegi_switch_user</value></property>
<property name="exitUserUrl"><value>/j_acegi_exit_user</value></property>
<property name="targetUrl"><value>/secure/index.htm</value></property>
</bean>
-->
<bean id="authenticationLoggerListener"
class="org.acegisecurity.event.authentication.LoggerListener" />
<bean id="authorizationLoggerListener"
class="org.acegisecurity.event.authorization.LoggerListener" />
</beans>
AcegiTestProvider類從AbstractUserDetailsAuthenticationProvider繼承,有兩個方法必須實現(xiàn)
additionalAuthenticationChecks()和retrieveUser()方法.retrieveUser返回UserDetails,UserDetails的實現(xiàn)可以包裝更多的信息.但在本例中幾乎沒什么太大的作用,僅僅是為了返回而重新定義了一個類
真正的驗證邏輯發(fā)生在additionalAuthenticationChecks方法里拋出異常就算用戶登錄失敗
package net.omw.utility;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;
public class AcegiTestProvider extends
AbstractUserDetailsAuthenticationProvider {
private String url;
private String port;
private String domain;
/*
* 驗證邏輯
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#additionalAuthenticationChecks(org.acegisecurity.userdetails.UserDetails, org.acegisecurity.providers.UsernamePasswordAuthenticationToken)
*
*/
@Override
protected void additionalAuthenticationChecks(UserDetails arg0,
UsernamePasswordAuthenticationToken arg1)
throws AuthenticationException {
// TODO Auto-generated method stub
String URL = url+":"+port;
String username=domain+"\\"+arg0.getUsername();
String password = arg0.getPassword();
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL,"ldap://172.18.0.42:389");
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.SECURITY_PRINCIPAL,
username);
env.put(Context.SECURITY_CREDENTIALS,password);
env.put("com.sun.jndi.ldap.connect.pool","true");
env.put("java.naming.referral","follow");
try{
new InitialLdapContext(env,null);
}
catch(NamingException e){
// Authentication failed
throw new UsernameNotFoundException(e.toString());
}
}
@Override
protected UserDetails retrieveUser(String arg0,
UsernamePasswordAuthenticationToken arg1)
throws AuthenticationException {
// TODO Auto-generated method stub
GrantedAuthority[] authorities = new GrantedAuthority[1];
authorities[0] = new GrantedAuthorityImpl("ROLE_SUPERVISOR");
String password = (String) arg1.getCredentials();
/*String username = "";
Object obj = arg1.getPrincipal();
if (obj instanceof UserDetails) {
username = ((UserDetails) obj).getUsername();
} else {
username = obj.toString();
}
*/
UserDetails userDetails = new UserDetailsImpl(authorities, password,
arg1.getName(), true, true, true, true);
//if(true)
// throw new AuthenticationCredentialsNotFoundException("t");
return userDetails;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
}
package net.omw.utility;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;
public class UserDetailsImpl implements UserDetails {
GrantedAuthority[] authorities;
String password;
String username;
boolean isAccountNonExpired;
boolean isAccountNonLocked;
boolean isCredentialsNonExpired;
boolean isEnabled;
UserDetailsImpl(GrantedAuthority[] authorities, String password,
String username, boolean isAccountNonExpired,
boolean isCredentialsNonExpired, boolean isEnabled,
boolean isAccountNonLocked) {
this.authorities = authorities;
this.isAccountNonExpired = isAccountNonExpired;
this.isAccountNonLocked = isAccountNonLocked;
this.isEnabled = isEnabled;
this.password = password;
this.username = username;
this.isCredentialsNonExpired = isCredentialsNonExpired;
}
@Override
public GrantedAuthority[] getAuthorities() {
// TODO Auto-generated method stub
return authorities;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return password;
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return username;
}
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return isAccountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return isAccountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return isCredentialsNonExpired;
}
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return isEnabled;
}
}
??? public static void main(String[] args){
????? Mozi mozi=new Mozi();
????? Horse w=new WhiteHorse();
????? Horse b=new BlackHorse();
????? mozi.ride(w);
????? mozi.ride(b);
??? }
}?
程序打印輸出:
ridding a horse
ridding a horse
原因就是對兩次ride方法的調(diào)用傳入的參量不同,但是它們的靜態(tài)類型是一樣的,都是 Horse;
這個過程在編譯時期就完成了。
java通過方法置換支持動態(tài)分派。比如 String s1="ab"; Object o=s1+"c"; String s="abc";
o.equals(s) 打印true? o.equals()方法執(zhí)行的是String類的equals()方法.java調(diào)用對象的
真實類型的方法,這就是動態(tài)分派。
雙重分派:
public abstract class Vistor{
protected void processStrig(Object e){
?if(e instanceof String){
???? String tmp=(String) e;
???? String need="'"+e+"'";
???? System.out.println(nedd);
?? }else if(e instanceof Integer){
?????? String need=e.toString();
?????? System.out.println(need);
??? }else if(e instanceof Date){
???????????? Date tmp=(Date) e;
???????????? String need="'"+tmp.toString()+"'";
??????? }
????? ....
??? }
}
public class ConcreteVisitor extends Visitor{
protected void processString(Object e){
???? super.processString(e);
?? }??
}
方法的調(diào)用Visitor v=new ConcreteVisitor(); v.processString(new String("tt"));
v.processString()方法在調(diào)用的時候會檢察v的真實類型,調(diào)用真實類型的方法,這個時候就
發(fā)生了一動態(tài)的單分派過程.當子類調(diào)用超類的方法的時候明顯的根據(jù)instanceof判斷的真實類
型去執(zhí)行不同的方法,又發(fā)生了一次動態(tài)分派的過程.這個就是雙重分派的實現(xiàn)。這種方法實現(xiàn)的
程序比較冗長和容易出錯.
“返傳球”方案:
public abstract class Vistor{
?? public abstract String processStrig(Object e);
}
public class ConcreteVisitor extends Visitor{
? public String processString(WrapperString e){
??? String tmp= t.toString();
??? System.out.println(tmp);
?? }??
? public String processInteger(WrapperInteger e){
??? String tmp=e.toString();
??? System.out.println(tmp);
?? }
}
public class abstract Wrapper{
? public abstract String processString(Vistor v);
}
public class WrapperString extends Wrapper{
? public String processString(Vistor v){
??? v.processString(this);
?? }
? public String toString(){
?? ...
?? }
}
public class WrapperInteger extends Wrapper{
??? public String processInteger(Visitor v){
???? v.processString(this);
??? }
??? public String toString(){
???? ...
??? }
?}
方法的調(diào)用:
Visitor v = new ConcreteVisitor();
Wrapper wrapper= new WrapperString();
wrapper.processString(v);
當wrapper.processString()方法執(zhí)行的時候會檢察wrapper的真實類型,這個就產(chǎn)生了一次
動態(tài)單分派,processString()里面的語句v.processString()在執(zhí)行的時候也會檢察v的真
實類型,動態(tài)雙重分派就發(fā)生了。
訪問者模式的核心就是“返傳球“方案的雙重分派。其示意性類圖:(注:虛線箭頭劃錯了)
在一個方法內(nèi)實現(xiàn)向不同的表插入不同數(shù)據(jù)的具體實現(xiàn)方案(簡化了的):因為整個方案里只需
要一個訪問者對象,因此使用簡化了的訪問者模式。因為java基本類型及對應的類是不變模式的
實現(xiàn):因此包裝一下這些基本類型和類并實現(xiàn)訪問者模式需要的方法。
public abstract class Wrapper {
??? public Wrapper() {
??? }
??? public abstract String action(Visitor visitor);
}
包裝Date類:
import java.util.Date;
public class WrapperDate extends Wrapper {
??? private Date date;
??? public WrapperDate(Date date) {
??????? this.date=date;
??? }
??? public String action(Visitor visitor){
???????? return( visitor.visit(this));
??? }
??? public String toString(){
??????? if (date==null){
??????????? return "null";
??????? }
??????? return "'"+date.toString()+"'";
??? }
}
包裝Integer類:
public class WrapperInteger extends Wrapper {
??? private Integer value;
??? public WrapperInteger(Integer value) {
??????? this.value=value;
??? }
??? public WrapperInteger(int value){
??????? this.value=new Integer(value);
??? }
??? public WrapperInteger(String value){
????? this.value=new Integer(value);
??? }
??? public String action(Visitor visitor){
?????? return( visitor.visit(this));
??? }
??? public String toString(){
??????? if(value==null){
??????????? return "null";
??????? }
??????? return value.toString();
??? }
}
包裝String類:
public class WrapperString extends Wrapper {
??? private String wrapper;
??? public WrapperString( String wrapper) {
??????? this.wrapper = wrapper;
??? }
??? public WrapperString( char[] wrap) {
??????? wrapper = new String(wrap);
??? }
??? public String action(Visitor visitor) {
??????? return (visitor.vistit(this));
??? }
??? public String toString() {
??????? if(wrapper==null){
??????????? return "null";
??????? }
??????? return "'" + wrapper + "'";
??? }
}
具體訪問者的實現(xiàn):
public class Visitor {
??? public Visitor() {
??? }
??? public String vistit(WrapperString wrap){
?????? return wrap.toString();
??? }
??? public String visit(WrapperInteger value){
??????? return value.toString();
??? }
??? public String visit(WrapperDate date){
??????? return date.toString();
??? }
}
具體應用類的實現(xiàn):
import java.util.*;
public class Test {
??? private Visitor visitor = new Visitor();
??? public Test() {
??? }
??? public Visitor getVisitor() {
??????? return visitor;
??? }
??
??? public int insertData(String tablename, List columNameCollection,
????????????????????????? List values) {
??????? StringBuffer query = new StringBuffer("insert into " + tablename + " (");
??????? int count = 0;
??????? for (Iterator it = columNameCollection.iterator(); it.hasNext(); ) {
??????????? String columName = (String) it.next();
??????????? query.append(columName);
??????????? query.append(",");
??????? }
??????? query.deleteCharAt(query.length() - 1);
??????? query.append(") values(");
??????? for (Iterator it = values.iterator(); it.hasNext(); ) {
??????????? Wrapper wrapper = (Wrapper) it.next();
??????????? String tmp = wrapper.action(getVisitor());
??????????? query.append(tmp);
??????????? query.append(",");
??????? }
??????? query.deleteCharAt(query.length() - 1);
??????? query.append(")");
??????? System.out.println(query.toString());
??????? return count;
??? }
??? public static void main(String[] args) {
??????? Test test = new Test();
??????? String tableName = "cutomer";
??????? List columNameCollection = new ArrayList();
??????? String columName = "name";
??????? String columAge = "age";
??????? String columFunctionTime="fuctiontime";
??????? columNameCollection.add(columName);
??????? columNameCollection.add(columAge);
??????? columNameCollection.add(columFunctionTime);
??????? List values = new ArrayList();
??????? String name=null;
??????? Wrapper wrapper1 = new WrapperString(name);
??????? Wrapper wrapper2 = new WrapperInteger(1);
??????? Wrapper wrapper3= new WrapperDate(new java.util.Date());
??????? values.add(wrapper1);
??????? values.add(wrapper2);
??????? values.add(wrapper3);
??????? test.insertData(tableName,columNameCollection,values);
???????
??? }
}
程序打印結(jié)果:
insert into cutomer (name,age,fuctiontime) values(null,1,'Sat Aug 12 13:46:58 CST 2006')
這個輸出是滿足MSSQL執(zhí)行插入的語法要求的.雖然這樣就實現(xiàn)了想要的結(jié)果,
但是insertData(String tablename, List columNameCollection, List values) 方法在每次調(diào)
用的時候需要輸入表名跟該表的列的集合,還是很麻煩,不盡人意,而且不同的數(shù)
據(jù)庫的表名是不一樣的,因此最好用配置文件來解決這一個問題.
歡迎加入QQ群:30406099?
?
?
參數(shù):
c - 要為其繪制邊框的組件
g - 繪制的圖形
x - 所繪制邊框的 x 坐標位置
y - 所繪制邊框的 y 坐標位置
width - 所繪制邊框的寬度
height - 所繪制邊框的高度
//附注:邊框就是在這個方法中給畫出來的
--------------------------------------------------------------------------------
Insets getBorderInsets(Component c)返回該邊框的 insets。
//附注一下:該類是容器邊界的表示形式。它指定容器必須在其各個邊緣留出的空間。這個空間可以是邊
//界、空白空間或標題。
參數(shù):
c - 要應用此邊框 insets 值的組件
--------------------------------------------------------------------------------
isBorderOpaque
boolean isBorderOpaque()返回此邊框是否透明。如果邊框為不透明,則在繪制它時將用自身的背景來填充。
接口的實現(xiàn)類? 至于畫圖用到的方法,詳見JAVA API.
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.border.*;
public class MyBorder implements Border
{
?//設(shè)置邊框四周留出的空間
? protected int m_w=6;??
? protected int m_h=6;
? protected int m_left=16;
//設(shè)置邊框的前景色跟背景色
? protected Color m_topColor = Color.white;
? protected Color m_bottomColor = Color.gray;
? public MyBorder() {
??? m_w=6;
??? m_h=6;
??? m_left=16;
? }
? public MyBorder(int w, int h) {
??? m_w=w;
??? m_h=h;
? }
? public MyBorder(int w, int h, Color topColor,
?? Color bottomColor) {
??? m_w=w;
??? m_h=h;
??? m_topColor = topColor;
??? m_bottomColor = bottomColor;
? }
? public Insets getBorderInsets(Component c) {
??? return new Insets(m_h, m_left, m_h, m_w);
? }
? public boolean isBorderOpaque() { return true; }
? public void paintBorder(Component c, Graphics gd,
?? int x, int y, int w, int h) {
??? Graphics2D g = (Graphics2D) gd;
??? w--;
??? h--;
??? g.setColor(m_topColor);
??? g.drawLine(x, y+h, x, y+m_h);
??? g.drawArc(x, y, 2*m_w, 2*m_h, 180, -90);
??? g.drawLine(x, y, x+w-m_w, y);
??? g.drawArc(x+w-2*m_w, y, 2*m_w, 2*m_h, 90, -90);
??? int stringHeitht = y+h-5;
??? Point2D.Float? p1 = new Point2D.Float(x,y+h);
??? Point2D.Float p2 = new Point2D.Float(x,y);
??? GradientPaint gradient = new GradientPaint(p1,Color.blue,p2,Color.gray,false);
??? //g.setColor(Color.YELLOW);
??? //g.drawRect();
??? g.setPaint(gradient);
??? g.fillRect(x,y,x+m_left,y+h);
??? g.setColor(Color.GRAY);
??? g.drawString("瓜",((x+m_left)-g.getFontMetrics().charWidth('傻'))/2,stringHeitht);
??? int simpleFontHeitht = g.getFontMetrics().getHeight();
??? stringHeitht-=simpleFontHeitht;
??? g.drawString("傻",((x+m_left)-g.getFontMetrics().charWidth('傻'))/2,stringHeitht);
??? g.setColor(m_bottomColor);
??? g.drawLine(x+w, y+m_h, x+w, y+h);
?? // g.drawArc(x+w-2*m_w, y+h-2*m_h, 2*m_w, 2*m_h, 0, -90);
?? g.drawLine(x, y+h, x+w, y+h);
??? //g.drawArc(x, y+h-2*m_h, 2*m_w, 2*m_h, -90, -90);
? }
}
剩下的就是把這個邊框給它裝上去了.在JMenu中有一個方法getPopupMenu()得到彈出菜單對象JPopupMenu;
然后調(diào)用這個JPopupMenu對象的setBorder方法就行了.下面是完整的測試程序
import java.awt.Toolkit;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.awt.Dimension;
public class Application1 {
? boolean packFrame = false;
? /**
?? * Construct and show the application.
?? */
? public Application1() {
??? MenuFaces frame = new MenuFaces();
??? // Validate frames that have preset sizes
??? // Pack frames that have useful preferred size info, e.g. from their layout
??? if (packFrame) {
????? frame.pack();
??? }
??? else {
????? frame.validate();
??? }
??? // Center the window
??? Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
??? Dimension frameSize = frame.getSize();
??? if (frameSize.height > screenSize.height) {
????? frameSize.height = screenSize.height;
??? }
??? if (frameSize.width > screenSize.width) {
????? frameSize.width = screenSize.width;
??? }
??? frame.setLocation( (screenSize.width - frameSize.width) / 2,
????????????????????? (screenSize.height - frameSize.height) / 2);
??? frame.setVisible(true);
? }
? /**
?? * Application entry point.
?? *
?? * @param args String[]
?? */
? public static void main(String[] args) {
??? SwingUtilities.invokeLater(new Runnable() {
????? public void run() {
??????? try {
????????? UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
??????? }
??????? catch (Exception exception) {
????????? exception.printStackTrace();
??????? }
??????? new Application1();
????? }
??? });
? }
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MenuFaces
??? extends JFrame {
? JPanel contentPane;
? BorderLayout borderLayout1 = new BorderLayout();
? JMenuBar jMenuBar1 = new JMenuBar();
? JMenu jMenuFile = new JMenu();
? JMenuItem jMenuFileExit = new JMenuItem();
? JMenuItem jMenuItem1 = new JMenuItem();
? JMenuItem jMenuItem2 = new JMenuItem();
? JMenuItem jMenuItem3 = new JMenuItem();
? JMenu jMenu1 = new JMenu();
? JMenuItem jMenuItem4 = new JMenuItem();
? public MenuFaces() {
??? try {
????? setDefaultCloseOperation(EXIT_ON_CLOSE);
????? jbInit();
??? }
??? catch (Exception exception) {
????? exception.printStackTrace();
??? }
? }
? /**
?? * Component initialization.
?? *
?? * @throws java.lang.Exception
?? */
? private void jbInit() throws Exception {
??? contentPane = (JPanel) getContentPane();
??? contentPane.setLayout(borderLayout1);
??? setSize(new Dimension(400, 300));
??? setTitle("Frame Title");
??? jMenuFile.setText("File");
??? jMenuFileExit.setText("Exit");
??? jMenuFileExit.addActionListener(new MenuFaces_jMenuFileExit_ActionAdapter(this));
??? jMenuItem1.setText("open");
??? jMenuItem2.setText("save");
??? jMenuItem3.setText("save as");
??? jMenu1.setText("other");
??? jMenuItem4.setText("tt");
??? jMenuBar1.add(jMenuFile);
??? jMenuBar1.add(jMenu1);
??? jMenuFile.add(jMenuItem3);
??? jMenuFile.add(jMenuItem2);
??? jMenuFile.add(jMenuItem1);
??? jMenuFile.add(jMenuFileExit);
??? jMenu1.add(jMenuItem4);
??? JPopupMenu tt = jMenuFile.getPopupMenu();
??? MyBorder myBorder = new MyBorder();
??? tt.setBorder(myBorder);
??? setJMenuBar(jMenuBar1);
? }
? /**
?? * File | Exit action performed.
?? *
?? * @param actionEvent ActionEvent
?? */
? void jMenuFileExit_actionPerformed(ActionEvent actionEvent) {
??? System.exit(0);
? }
}
class MenuFaces_jMenuFileExit_ActionAdapter
??? implements ActionListener {
? MenuFaces adaptee;
? MenuFaces_jMenuFileExit_ActionAdapter(MenuFaces adaptee) {
??? this.adaptee = adaptee;
? }
? public void actionPerformed(ActionEvent actionEvent) {
??? adaptee.jMenuFileExit_actionPerformed(actionEvent);
? }
}
歡迎加入QQ群:30406099?
?