2015-02-21 11:23

[轉載] [Java] BigDecimal的四則運算

轉載自:[Java] BigDecimal的四則運算

最近因為需要計算報表中的房物出租率,會用到BigDecimal的運算,目前只知道int, double, float等基本型態的我,連BigDecimal是三小都不太清楚,後來查了許多資料才知道原來BigDecimal可以用在精確的數學計算上面,許多商業用報表都需要用到BigDecimal型別。

BigDecimal有兩個較常用到的方法:
  1. BigDecimal(double val)
    Translates a double into a BigDecimal.
  2. BigDecimal(String val)
    Translates the String repre sentation of a BigDecimal into a BigDecimal.

API將上述方法解釋的非常清楚,而我們如果要精確計算,一定得把數值轉型成String型別,否則得到的結果會是有問題的。簡單來說,若要使用BigDecimal做加法計算必須有以下步驟:
  1. 需要先將兩個浮點數(double)轉為String,並分別宣告為BigDecimal
  2. 在其中一個浮點數使用add方法,傳入另一個浮點數作為參數
  3. 作為運算結果的參數(答案)也須宣告為BigDecimal
  4. 最後把運算的結果(BigDecimal)再轉換為浮點數

在BigDecimal的運算中,加為add, 減為sub,乘為multiply,除法為divide。在做運算之前需針對每一個變數new BigDecimal物件,舉例如下:
// 精確的加法運算,v1 為加數,v2 為被加數,return v1 + v2
public static double add(double v1,double v2){
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    return b1.add(b2).doubleValue();
}

在運算之後若需四捨五入該怎麼辦呢?舉例如下:
// v 為需要四捨五入的數字,scale 為小數點後面要保留幾位數,return 四捨五入後的結果
public static double round(double v,int scale){
    if(scale < 0){
        throw new IllegalArgumentException(
            "The scale must be a positive integer or zero"
        );
    }
    BigDecimal b = new BigDecimal(Double.toString(v));
    BigDecimal one = new BigDecimal("1");
    return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}

完整範例請參考以下文字:
import java.math.BigDecimal;
public class Testtest {

    public static void main(String[]args){
 
        // 宣告第一個需要運算的數值
        BigDecimal bigNumber = new BigDecimal("89.1234567890123456789"); 
  
        // 宣告第二個需要運算的數值
        BigDecimal bigRate = new BigDecimal(1000); 
  
        // 宣告運算後的答案為 bigResult
        BigDecimal bigResult = new BigDecimal(0);
  
        // bigResult 為 bigNumBer * bigRate
        bigResult = bigNumber.multiply(bigRate); 
  
        // 印出 bigResult
        System.out.println(bigResult.toString()); 
  
        // 將 bigNumber 四捨五入變為 double 型態
        double dData = bigNumber.doubleValue(); 
  
        // 印出 dDate
        System.out.println(dData);
  
        // 宣告 data2 為 bigNumber/bigRate 並四捨五入至小數點第二位
        double data2 = bigNumber
                           .divide(bigRate,2,BigDecimal.ROUND_HALF_UP)
                           .doubleValue();
  
        // 印出 data2
        System.out.println(data2);
    }
}

2015-02-21 11:03

[Java] System Property 筆記

String version = System.getProperty("java.version");

java.versionJava 執行期環境版本
java.vendorJava 執行期環境供應商
java.vendor.urlJava 供應商的 URL
java.homeJava 安裝目錄
java.vm.specification.versionJava 虛擬機規範版本
java.vm.specification.vendorJava 虛擬機規範供應商
java.vm.specification.nameJava 虛擬機規範名稱
java.vm.versionJava 虛擬機實現版本
java.vm.vendorJava 虛擬機實現供應商
java.vm.nameJava 虛擬機實現名稱
java.specification.versionJava 執行期環境規範版本
java.specification.vendorJava 執行期環境規範供應商
java.specification.nameJava 執行期環境規範名稱
java.class.versionJava 類別格式版本號
java.class.pathJava 類別路徑
java.library.path加載庫時搜索的路徑串列(linked-list)
java.io.tmpdir預設的暫時檔路徑
java.compiler要使用的 JIT 編譯器的名稱
java.ext.dirs一個或多個擴展目錄的路徑
os.name作業系統 的名稱
os.arch作業系統 的架構
os.version作業系統 的版本
file.separator檔分隔設定(在 UNIX 系統中是“/”)
path.separator路徑分隔設定(在 UNIX 系統中是“:”)
line.separator行分隔設定(在 UNIX 系統中是“/n”)
user.name用戶的賬戶名稱
user.home用戶的主目錄
user.dir用戶的當前工作目錄


List all system properties
Properties props = System.getProperties();
props.list(System.out);
2015-02-21 10:55

[Java] ServletRequest 筆記

Request URL
http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S%3F+ID?p+1=c+d&p+2=e+f#a

MethodURL DecodedResult
getContextPath()/app
getLocalAddr()127.0.0.1
getLocalName()30thh.loc
getLocalPort()8480
getMethod()GET
getPathInfo()yes/a?+b
getProtocol()HTTP/1.1
getQueryString()nop+1=c+d&p+2=e+f
getRequestedSessionId()noS%3F+ID
getRequestURI()no/app/test%3F/a%3F+b;jsessionid=S+ID
getRequestURL()nohttp://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S+ID
getScheme()http
getServerName()30thh.loc
getServerPort()8480
getServletPath()yes/test?
getParameterNames()yes[p 2, p 1]
getParameter("p 1")yesc d

2015-02-14 15:18

VMware Authorization Service 無法啟動

在 VMware 啟動虛擬機時發生了 Service "VMware Authorization Service" did not start. 的錯誤訊息,原因是相依的 vmx86 服務遺失了,可以透過以下指令重建服務:

sc create vmx86 type= kernel start= auto binpath= "C:\Program Files (x86)\VMware\VMware Workstation\vmx86.sys" displayname= "VMware Virtualization Driver"
2015-02-10 15:52

JAX-WS RI + Spring 4 自動 Exporting Service

Spring 4 的部分我就不多說了,請自行配置 jar 檔,這裡我用 jaxws-ri-2.2.10.zipjaxws-spring-1.9.jar 進行配置。


AccountService.java
package test.jaxws.webservice;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface AccountService {

    @WebMethod
    void insertAccount(String acc);

    @WebMethod
    String[] getAccounts(String role);
}
先來定義一個 interface,這主要是給 Client 用的。


AccountServiceImpl.java
package test.jaxws.webservice;

import javax.jws.WebMethod;
import javax.jws.WebService;
import org.springframework.stereotype.Component;

@Component
@WebService(serviceName="AccountService")
public class AccountServiceImpl implements AccountService {

    @Override
    @WebMethod
    public void insertAccount(String acc) {
    }

    @Override
    @WebMethod
    public String[] getAccounts(String role) {
        return new String[] {"tom", "jax"};
    }
}
接者是 Web Service 的主體,@Component 是為了讓 Spring component-scan 自動建立 Bean,@WebService 則是用定義要 Exporting 到 JAX-WS 的 serviceName,由於是透過 Spring 去管理 bean 所以可以用 @Autowired 引用其他資源。


JaxWsRtServletServiceExporter.java
package test.jaxws.webservice;

import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.jws.WebService;
import javax.xml.ws.WebServiceProvider;

import org.jvnet.jax_ws_commons.spring.SpringService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.SingletonBeanRegistry;
import com.sun.xml.ws.transport.http.servlet.SpringBinding;

public class JaxWsRtServletServiceExporter implements BeanFactoryAware, InitializingBean {

    private ListableBeanFactory beanFactory;
    private String basePath;

    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        if (!(beanFactory instanceof ListableBeanFactory)) {
            throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory");
        }
        this.beanFactory = (ListableBeanFactory) beanFactory;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (this.beanFactory instanceof SingletonBeanRegistry == false) { return; }

        SpringService service = new SpringService();

        Set<String> beanNames = new LinkedHashSet<String>(this.beanFactory.getBeanDefinitionCount());
        beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames()));

        if (this.beanFactory instanceof ConfigurableBeanFactory) {
            beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames()));
        }

        SingletonBeanRegistry factory = (SingletonBeanRegistry)this.beanFactory;

        for (String beanName : beanNames) {
            try {
                Class<?> type = this.beanFactory.getType(beanName);
                if (type == null || type.isInterface()) { continue; }

                WebService wsAnnotation = type.getAnnotation(WebService.class);
                WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class);
                if (wsAnnotation == null && wsProviderAnnotation == null) { continue; }


                String serviceName;
                if (wsAnnotation != null) {
                    serviceName = wsAnnotation.serviceName();
                } else {
                    serviceName = wsProviderAnnotation.serviceName();
                }

                service.setImpl(type);
                service.setBean(this.beanFactory.getBean(beanName));

                SpringBinding springBinding = new SpringBinding();
                springBinding.setBeanName(serviceName + "Binding");
                springBinding.setUrl(this.basePath + "/" + serviceName);
                springBinding.setService(service.getObject());

                factory.registerSingleton(serviceName + "Binding", springBinding);
            }
            catch (CannotLoadBeanClassException ex) {
                // ignore beans where the class is not resolvable
            }
        }
    }
}
為了可以自動 Exporting Service 到 JaxWs RI Servlet 需要建立一個 Exporter,這裡將具有 @WebService 或 @WebServiceProvider 的 Bean 包裝成 SpringBinding 再註冊到 Spring BeanFactory 裡,這樣 WSSpringServlet 就會取到這邊註冊 SpringBinding Bean 進行 Exporting。


web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns="http://java.sun.com/xml/ns/javaee" 
 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
 version="3.0"
>
 <display-name>test-jaxws-rt</display-name>

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/jaxws.xml</param-value>
 </context-param>

 <context-param>
     <param-name>webAppRootKey</param-name>
     <param-value>test-jaxws-rt.root</param-value>
   </context-param> 
 
 <servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/dispatcher.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

    <servlet>
        <servlet-name>jaxws-servlet</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jaxws-servlet</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>
</web-app>
在 web.xml 同時註冊兩個 servlet,分別是 Spring MVC 的 DispatcherServlet 跟 JAX-WS 的 WSSpringServlet,這邊主要是透過 ContextLoaderListener 去啟用全域的 ApplicationContext 去管理所有的 Bean。


jaxws.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
    <context:component-scan base-package="test.jaxws.webservice" />

    <bean id="jaxWsRtServletServiceExporter" class="test.jaxws.webservice.JaxWsRtServletServiceExporter">
        <property name="basePath" value="/service"/>
    </bean>
</beans>
jaxws.xml 是給 ContextLoaderListener 的設定,這裡用 component-scan 去找出 test.jaxws.webservice 下有 @Component 的 Bean,以及用 JaxWsRtServletServiceExporter 去轉換所有的 @WebService 到 SpringBinding。


dispatcher.xml
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
    <context:component-scan base-package="test.jaxws.controller" />

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <bean id="accountWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean" scope="request">
        <property name="serviceInterface" value="test.jaxws.webservice.AccountService"/>
        <property name="wsdlDocumentUrl" value="http://localhost:8090/test-jaxws-rt/service/AccountService?wsdl"/>
        <property name="namespaceUri" value="http://webservice.jaxws.test/"/>
        <property name="serviceName" value="AccountService"/>
        <property name="portName" value="AccountServiceImplPort"/>
    </bean>
</beans>
在這裡用 JaxWsPortProxyFactoryBean 去建立 WebService Client,因為是同一個 Web Content 所以用 scope="request" 延遲建立。


HomeController.java
package test.jaxws.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;

import test.jaxws.webservice.AccountService;

@Controller
public class HomeController {

    @Autowired
    private WebApplicationContext appContent;

    @RequestMapping("/")
    public ModelAndView index() {
        AccountService service = appContent.getBean("accountWebService", AccountService.class);
        String[] users = service.getAccounts("user");

        ModelAndView model = new ModelAndView("index");
        model.addObject("users", users);

        return model;
    }
}
接下來就是連接的 Client,這邊用 WebApplicationContext 延遲取得 AccountService,在 http://localhost:8080/test-jaxws-rt/service/AccountService 就可以看到 service 的主頁面。


參考資料:
JAX-WS + Spring integration example
22. Remoting and web services using Spring
2015-02-06 13:01

[轉載] spring 的配置文件中 mvc:view-controller path 使用方法

1、重定向
<mvc:view-controller path="/" view-name="redirect:/admin/index"/>
即如果当前路径是 / 则重定向到 /admin/index


2、view name
<mvc:view-controller path="/" view-name=admin/index"/>
如果当前路径是 / 则交给相应的视图解析器直接解析为视图


<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="2">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="contentType" value="text/html"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
则得到的视图时 /WEB-INF/jsp/admin/index.jsp


不想进 controller,可以在 spring-mvc.xml 中配置静态访问路径
<!-- 访问静态资源文件  -->
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>

像这样,jsp 文件若放在静态路径 /images 下,可以直接访问,而不经过 controller。
2015-02-06 12:48

[轉載] Spring Bean Scope

轉載自:Spring Bean Scope 學習

在 Spring 中定義一個 Bean 時,可以針對其 scope 加以設定。在新版的 Spring 中,共有五種不同的 scope 可以設定,分別為:
singleton
在 Spring IoC Container,該 bean 只會有單一實例(a single instance),此為 Spring 預設值
prototype
在 Spring IoC Container 中,該 bean 可以有多個實例(any number of object instances)
request
在每一次的 HTTP Request,spring container 會根據 loginAction bean 的定義來建立一個全新的 instance,而且僅在目前的 request 中有效,所以可以放心的去更改 instance 的內部狀態,請求結束,request scope 的 bean instance 會被 destroy
session
針對某個 HTTP Session,spring container 會根據 userPreference bean 的定義來建立一個全新的 instance,同樣的,和 request scope 一樣,可以放心的去更改 instance 內部狀態。
global-session
僅在 portlet 為基礎的 Web 應用下有作用。Porlet 的規範中定義了 global session 的概念。


在定義 scope 時,會在 bean 中定義如下:
<bean id="helloWorld" class="HelloWorld" scope="singleton">

當 scope 設定為 singleton 時,整個 container 只會有一個 instance,所以下方的 obj 和 obj1 都會是同一個 instance。
ApplicationContext context = new ClassPathXmlApplicationContext("Bean.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.setMessage("hello");
obj.getMessage();
HelloWorld obj1 = (HelloWorld) context.getBean("helloWorld");
obj1.getMessage();


<bean id="helloWorld" class="HelloWorld" scope="prototype">

如果設定為 prototype 時,obj 和 obj1 將會是不同的 instances,可以分別進行操作。在這裡,singleton 的單一 instance 是用 id 來進行識別,不同 id、相同 class 時,還是可以有多個 instances(getBean傳入不同的id即可)。


request、session 和 global-session 三種 scope 只能在 web 環境中使用,如果在非 web 環境設定,會出現【No Scope registered for scope 'request'】的錯誤。
2015-01-31 21:02

[轉載] PHP 配置open_basedir,让各虚拟站点独立运行

轉載自:PHP 配置open_basedir,让各虚拟站点独立运行 - canbeing - 博客园

open_basedir 可将用户访问文件的活动范围限制在指定的区域,通常是其家目录的路径,也可用符号"."来代表当前目录。open_basedir 也可以同时设置多个目录, 在 Windows 中用分号(;)分隔目录,在任何其它系统中用冒号(:)分隔目录。当其作用于 Apache 模块时,父目录中的 open_basedir 路径自动被继承。

以下以 Linux 系统下的配置为例:

方法一:在 php.ini 里配置
open_basedir = .:/tmp/

方法二:在 Apache 配置的 VirtualHost 里设置
php_admin_value open_basedir .:/tmp/

方法三:在 Apache 配置的 Direcotry .htaccess 里设置
php_admin_value open_basedir .:/tmp/


关于三个配置方法的解释:
  1. 方法二的优先级高于方法一,也就是说方法二会覆盖方法一
    方法三的优先级高于方法二,也就是说方法三会覆盖方法二
  2. 配置目录里加了 /tmp/ 是因为php默认的临时文件(如上传的文件、session 等)会放在该目录,所以一般需要添加该目录,否则部分功能将无法使用
  3. 配置目录里加了 . 是指运行php文件的当前目录,这样做可以避免每个站点一个一个设置
  4. 如果站点还使用了站点目录外的文件,需要单独在对应 VirtualHost 设置该目录