AngularJS初心者がハマりがちなこと

ng-repeatで回数を指定する

listSize=$scope.items.listSize;
$rootScope.range = function(listSize) {
    var arr = [];
    for (var i=0; i<listSize; ++i) arr.push(i);
    return arr;
};

listSizeに回数を指定します。

参考リンク:AngularJS tips - ng-repeat で配列ではなく数値で for ループする方法

ng-repeatの罠

ng-repeatを使う場合、ループ内ではinで指定した変数しか参照できません。

<tr ng-repeat="i in range(items.listSize-1)">
  <td>{{i+1}}</td>
  <td ng-if="$parent.items.obpTop10[i].rank == 1" bgcolor="#FC9898">{{$parent.items.obpTop10[i].name}}/{{$parent.items.obpTop10[i].obp | number:4}}</td>
  <td ng-if="$parent.items.obpTop10[i].rank != 1">{{$parent.items.obpTop10[i].name}}/{{$parent.items.obpTop10[i].obp | number:4}}</td>
  <td ng-if="$parent.items.twobaseTop10[i].rank == 1" bgcolor="#FC9898">{{$parent.items.twobaseTop10[i].name}}/{{$parent.items.twobaseTop10[i].twobase}}本</td>
  <td ng-if="$parent.items.twobaseTop10[i].rank != 1">{{$parent.items.twobaseTop10[i].name}}/{{$parent.items.twobaseTop10[i].twobase}}本</td>
  <td ng-if="$parent.items.slgTop10[i].rank == 1" bgcolor="#FC9898">{{$parent.items.slgTop10[i].name}}/{{$parent.items.slgTop10[i].slg | number:4}}</td>
  <td ng-if="$parent.items.slgTop10[i].rank != 1">{{$parent.items.slgTop10[i].name}}/{{$parent.items.slgTop10[i].slg | number:4}}</td>
  <td ng-if="$parent.items.fourBallTop10[i].rank == 1" bgcolor="#FC9898">{{$parent.items.fourBallTop10[i].name}}/{{$parent.items.fourBallTop10[i].fourBall}}個</td>            

$scopeなどの中身を参照する場合は$parentで親のスコープを参照する必要があります。 AngularJS でループ外のスコープにアクセスする ”AngularJS ループ外”→"ng-repeat スコープ"などでググってたどり着きました。

iはインデックス(添え字)です。

前述した回数指定を行ってループさせながらインデックスで配列にアクセスする方法です。

PKIX path building failed:javaにSSL証明書を追加する話。

個人的に開発しているWEBアプリで、
あるWEBサービスAPIを叩きにいくのだが、
最近ドメインが変わった後にどうも(こちら側に)不具合が発生していた模様。
システムエラーが起こった場合はslackに連携するようにしていたのだが、
リダイレクト先が変わったことによって本来の処理まで行っておらず、
結果的にシステムエラーさえ起きなかったという…。

リダイレクト先を修正してローカル環境で動かすと、
com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
REST通信に失敗し、上記エラーメッセージが出ていた。

javaでSSL接続をすると、PKI PATHの構築に失敗となる
なるほど、相手ホストを信頼済みのリストに登録すればよいのか。
InstallCert.javaがリンク切れになってたので探すとgithubにあった。
github.com
qiita.com
keytoolを使ってcacertsに証明書を追加すればよいわけですな。
InstallCertのREADMEが一番わかりやすかった。

とりあえずローカル環境で動くことを確認して本番機に反映。

イヤホン修理。

いつもはソフトウェアエンジニア(プログラマ)として働いたり、
趣味でコーディングしたりしていますが、
今回は断線してしまったイヤホンのプラグ交換。
ネットにいくつか交換方法が載ってたので、結構参考になりました。

段ボールに刺して固定するのはナイスアイディアだと思いました。
d.hatena.ne.jp

ページング多すぎてうざかったですけど一番わかりやすかった。
monostudio.jp


f:id:ckoshien:20170202155110j:plain
上から
・半田付け後にボンドで固めたところ
・根本を熱収縮チューブで固定
・付属のカバーをつける
・完成
半田ごてを使うのは中学の技術の授業と
折れた傘の骨を無謀にも半田で接着しようとしたころですかね。
もう15年ぐらい半田ごて触ってなかったです。

広告を非表示にする

S2Chronos始めました(今更)

趣味で開発している野球リーグスコア管理システム
バッチ処理を新たに2つほど追加しました。

  • 30日間天気予報取得バッチ(6時間ごと)
  • 決め太郎スケジュール変更監視バッチ(4時間ごと)

使っているFWがSAStruts(Seasar2)なのでバッチはS2Chronos
少し設定ファイル書いてやればそのままデプロイできるので割と便利。

@Task
@CronTrigger(expression = "0 0 */6 * * ?")//6時間ごと
public class GetWeatherTask {
	@Resource
	public WeatherService weatherService;
	public List<Weather> weatherList;
	public HashMap<String,WeatherDto> response;

	private static Logger logger = Logger.getLogger("rootLogger");
	// タスク処理
	public void doExecute() {
		weatherList=weatherService.findAllOrderByRegTime();
		response=new HashMap<String,WeatherDto>();
		//テーブル全データ削除
		long t3=System.currentTimeMillis();
		for(int i=0;i<weatherList.size();i++){
			weatherService.delete(weatherList.get(i));
		}
		long t4=System.currentTimeMillis();
		WeatherAction weatherAction =new WeatherAction();
		response=weatherAction.get();
		long t5=System.currentTimeMillis();
		String date="";
		WeatherDto weatherDto= new WeatherDto();
		for(Map.Entry<String, WeatherDto> e : response.entrySet()) {
			date=e.getKey();
			weatherDto=e.getValue();
			Weather weatherBean= new Weather();
			BeanUtil.copyProperties(weatherDto, weatherBean);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
			java.util.Date formatDate = null;
			String todayStr= new SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()).replaceAll("-", "/");
			int year=Calendar.getInstance().get(Calendar.YEAR);
			java.util.Date today=null;
			try {
				formatDate = sdf.parse(year+"/"+date);
				today=sdf.parse(todayStr);
			} catch (ParseException e1) {
				e1.printStackTrace();
			}
			if(today.compareTo(formatDate)>0){
				weatherBean.date=Date.valueOf(String.valueOf(year+1)+"-"+date.replaceAll("/", "-"));
			}else{
				weatherBean.date=Date.valueOf(String.valueOf(year)+"-"+date.replaceAll("/", "-"));
			}
			weatherService.insert(weatherBean);
		}
		long t6=System.currentTimeMillis();
		logger.info("天気テーブル全削除:"+(t4-t3));
		logger.info("天気データ取得:"+(t5-t4));
		logger.info("天気データinsert:"+(t6-t5));
		logger.info("タスク終了");
	}
}

Java7のソートにバグがあるの初めて知った。
Listのソートをする際にComparator使うやり方で、

Collections.sort(rbiTop10, new RbiComparator());
Collections.reverse(rbiTop10);

Collections.sortを使うと
Comparison method violates its general contract!
というエラーが返される。
調べてみたら既知のバグらしいが...。
http://blog.satotaichi.info/timsort-was-broken/
回避方法はいくつか試したけどJDKを6に落とせばバージョンが古いと怒られ...。
Collections.sortでも必ずエラーとなるわけではなく、
上記コードの前に要素数が同じソートをやっているが何も起こらずじまい。
とりあえず怖いので使わないことに越したことはないかと。
最悪自前でインデックスソートとかなら書けるはず...ずいぶん使ってないけど。
SQLでorder byすることもできなくはないけど1ページで同じ結果を複数用意するのに
何本もSQLを流していいものか...。

コーディングのリハビリ始めました。
seasar2とかしばらく使ってなかったのであちこちでエラー出して行き詰まるw
バリデータ関係もようやく少しずつ思い出してきたけど、
こういうやり方できるんだね。input="***.jsp"しか教わらなかったから新鮮。
#バリデートに引っかかったらメソッドを再度実行
@Execute(validator = true,input="(メソッド名)?redirect=true")
(参考)http://yakinikunotare.boo.jp/orebase2/sastruts/input_check
DBにアクセスするメソッドだとjspだけ呼ぶと入力値が空だったりするので。