読者です 読者をやめる 読者になる 読者になる

GuavaのImmutable Collectionsの実装サンプル

GuavaのImmutable Collectionsを見てみる。 (Java 9 のCollections APIでも同様のstatic factory methodが実装予定)

一般にImmutableであると、参照効率が良い, スレッドセーフなどのメリットがある。 github.com

以下、サンプル。

public static void main( String[] args )
{
    // static factory patternで宣言
    List<String> signals = ImmutableList.of("red","yellow","green");
    signals.add("pink"); // throw new UnsupportedOperationException


    // 初期化時の処理はbuilderも使用可能
    ImmutableList.Builder<String> pokemonBuilder = ImmutableList.builder();
    pokemonBuilder.add("zenigame");
    pokemonBuilder.add("hitokage", "hushigidane"); // 可変長引数も代入可能

    List<String> pokemonAtGoldAndSilver = Lists.newArrayList("waninoko", "hinoarashi", "tikorita");
    pokemonBuilder.addAll(pokemonAtGoldAndSilver); // Iterable型も代入可能

    List<String> pokemon = pokemonBuilder.build();
    pokemon.add("pikachu"); // throw new UnsupportedOperationException
}

Jinja2を試してみた(Python テンプレートエンジン)

PythonのテンプレートエンジンであるJinja2を使って、 信号機の色を出力する簡単なサンプルを作ってみる。

Welcome | Jinja2 (The Python Template Engine)

インストー

環境はMBPローカル。pipですぐにインストールできる。

$ pip install jinja2

実装サンプル

signals.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('./', encoding='utf8'))
tmpl = env.get_template('tmpl.txt')

signals = []
signals.append({'color':'blue'})
signals.append({'color':'yellow'})
signals.append({'color':'red'})

output = tmpl.render({'title':'signal color', 'signals':signals})

f = open('output.txt', 'w')
f.write(output)
f.close()

tmpl.txt

{{ title }}
{% for signal in signals -%}
 - {{ signal.color }}
{% endfor  %}

実行結果

output.txt

signal color
- blue
- yellow
- red

Spring Security 実装サンプル

Spring Securityのチュートリアルをやってみたのでメモ。 最低限必要なものは主に3つ。

1. Spring Security設定クラス

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 認可対象外の設定
        web.ignoring().antMatchers("/favicon.ico", "/css/**", "/js/**", "/img/**"); 
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {

        // mypage以下は認可対象とする。
        http.authorizeRequests()
                .antMatchers("/mypage**")
                .authenticated();

        // ログイン設定
        http.formLogin()
                .loginProcessingUrl("/login")
                .loginPage("/loginForm")
                .failureUrl("/loginForm?error")
                .defaultSuccessUrl("/", true)
                .usernameParameter("username")
                .passwordParameter("password");

        // 認証用cookie1ヶ月保持
        http.rememberMe()
                .tokenValiditySeconds(86400);

        // /logoutにpostするだけでログアウト
        http.logout()
                .logoutUrl("/logout**")
                .logoutSuccessUrl("/loginForm");
    }

    @Configuration
    static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
        @Autowired
        AccountDetailsService accountDetailsService;

        @Autowired
        PasswordEncoder passwordEncoder;

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(accountDetailsService)
                    .passwordEncoder(passwordEncoder);
        }
    }

}

2. 認証オブジェクトクラス

public class AccountDetails implements UserDetails {
    private final User user;

    public AccountDetails(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return AuthorityUtils.createAuthorityList("DEMO");
    }

    public User getUser() {
        return user;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getEmail();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

3. 認証オブジェクト生成, チェッククラス

@Service
public class AccountDetailsService implements UserDetailsService {

    @Autowired
    AccountRepository accountRepository;

    @Autowired
    ExceptionProvider exceptionProvider;

    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        return Optional.ofNullable(accountRepository.findOne(email))
            .map(AccountDetails::new)
            .orElseThrow(() -> new UsernameNotFoundException(
                "user specified by " + email + " is not found!"
            ));
    }
}

Spring Securityの概要

Spring Securityについて勉強した時のメモ。 ほぼTERASOLUNA Projectのドキュメントの内容です。 9.1. Spring Security概要 — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.3.0.RELEASE documentation

概要

  • Spring Securityとは、Webアプリケーションにセキュリティ対策機能を実装するときに利用されるフレームワーク
  • 基本機能として大きく分けて次の2つの機能を持つ。
    • 認証:ユーザの正当性を確認する作業。
    • 認可:アプリケーションが提供するリソースや処理に対して、アクセスを制御する機能。
  • 他にもセキュリティ強化のため下記の機能を持つ。
    • セッション管理機能:セッションのライフサイクル管理, セッションハイジャック対策, セッション固定攻撃対策
    • CSRF対策機能:CSRF対策
    • ブラウザセキュリティ機能連携:レスポンスヘッダによってブラウザが提供するセキュリティ機能と連携する

フレームワーク処理

  • FilterChainProxy

    • フレームワーク処理のエントリーポイント
    • サーブレットフィルタークラス
    • 全体的な処理の流れの制御をしており、実際のセキュリティ対策処理は SecurityFilterChain が行なっている。
  • HttpFireWall

    • HttpServletRequestHttpServletResponseに対してファイヤーウォール機能を提供するもの。
    • DefaultHttpFireWallにはディレクトリトラバーサル攻撃やHTTPレスポンス分割攻撃に対するチェックなどが実装されている。
  • SecurityFilterChain

    • FilterChainProxyが受け取ったリクエストに対して、適用するSecurity Filterの管理をするインターフェイス
    • リクエストURIによって、適用するSecurity Filterの管理をすることができる。
    • SecurityFilterクラスの種類
      • SecurityContextPersistenceFilter:リクエストを跨いでユーザの認証情報を共有する機能を提供するクラス。デフォルトではHttpSessionに認証情報を格納して実現している。
      • UsernamePasswordAuthenticationFilter:リクエストパラメータで指定されたユーザ名とパスワードを用いて認証処理を行うクラス。
      • LogoutFilter:ログアウト処理を行うクラス
      • FilterSecurityInterceptor:HTTPリクエスト(HttpServletRequest)に対して認可処理を実行するクラス。
      • ExceptionTranslationFilter:FIlterSecurityInterceptorで発生した例外をハンドリングするクラス。

Spring BootのMethod Validation

@ControllerクラスのPathVariableを、Spring Bean ValidationのMethod Validationで行った。 当初@Configurationクラスに下記のような設定が必要かと思われたが、公式リファレンスを見ると必要ないみたい。 (Spring boot 1.5.2.RELEASE version以上で必要ないことを確認している)

@Configuration
public AppConfig {

    @Bean
    LocalValidatorFactoryBean localValidatorFactoryBean() {
        return new LocalValidatorFactoryBean();
    }

    @Bean
    MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
        methodValidationPostProcessor.setValidator(localValidatorFactoryBean());
        return methodValidationPostProcessor;
    }
}

Method Validationは↓のように、クラスに対して@Validatedアノテーションを追加するだけで良い。 Spring Boot Reference Guide

@Controller
@Validated
public class CategoryController {

    @RequestMapping(value = "/{hoge}")
    public String showHoge(@PathVariable("hoge") @Size(min = 8, max = 10) final String hoge) {
        return "hoge";
    }
}

git logを見やすくする

git log がキレイに見える方法があった。

qiita.com

便利なので、gitconfigのaliasに入れておく。 (--decorate=fullはチカチカしすぎていたので、--decorateのみとした)

[alias]
  graph = log --graph --oneline --decorate

Java8 Stream API 簡単なサンプルコード

Stream APIを書く機会があったので、 簡単なサンプルコードを書いてみた。

import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {

        List<String> array = Arrays.asList("A", "B", "C", "A", "B");

        // filter
        System.out.println("filter---------------");
        array.stream()
            .filter(value -> value == "A")
            .forEach(value -> System.out.println(value));

        // limit
        System.out.println("limit---------------");
        array.stream()
            .limit(3)
            .forEach(value -> System.out.println(value));

        // distinct
        System.out.println("distinct---------------");
        array.stream()
            .distinct()
            .forEach(value -> System.out.println(value));

        // sorted
        System.out.println("sorted---------------");
        array.stream()
            .sorted()
            .forEach(value -> System.out.println(value));

        // map
        System.out.println("map---------------");
        array.stream()
            .map(s -> s.toLowerCase())
            .forEach(value -> System.out.println(value));

        // reduce
        System.out.println("reduce---------------");
        String collectedStr = array.stream()
            .reduce((s, t) -> s + t)
            .get();
        System.out.println(collectedStr);
    }
}