ちゃぱてぃ商店IT部 @ ウィキ
http://w.atwiki.jp/chapati4it/
ちゃぱてぃ商店IT部 @ ウィキ
ja
2024-02-29T13:18:08+09:00
1709180288
-
C言語/サンプル/CSVファイルの読込ソート出力2
https://w.atwiki.jp/chapati4it/pages/39.html
CSVファイルを読み込みソートして出力するサンプル(qsort, strtok使用版)です。
* 目次
#contents(fromhere=true)
* ポイント
+ CSVファイルを読み込んで、一行ずつ構造体にセットします。
++ strtok関数で","または"\nの位置を探して項目の文字を取り出します。
++ strtok関数は、元の文字列に\0を差し込む事で、簡単に文字列を取り出せるようにしているみたいです。
+ 構造体の配列をソートします。
++ 項目ごとに分割しているので、好きな項目でソートできます。
++ qsortで使うRecord構造体比較関数compRecordを作ります。
++ qsortのパラメータは1.ソートするデータの配列 2.ソートするデータの個数 3.データ一個あたりのサイズ 4.比較関数のポインタです。
+ 構造体をCSV形式で出力します。
++ fprintf(fp, "%d","%s","%s", ...)でごりごりっと出力します。
前回[[C言語/サンプル/CSVファイルの読込ソート出力]]を作った後で、qsort関数とstrtok関数の存在を知ったので
今回はqsort strtok関数を使って修正しました。
きっと、自力でバブルソートするより早いし、ソースコードもちょっとすっきりしました。
* サンプルソース
#highlight(c){{
// C言語/サンプル/CSVファイル読込sort出力
// CSVファイルを読み込んで、構造体に設定しソートしてから再度CSVファイルに出力するサンプルです。
// qsort strtok使用版
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Record構造体
struct Record {
// インデックス
int idx;
// タイトル
char title[100];
// 日付
char date[11];
};
// CSVファイルから読み込んだ文字列をRecord構造体に設定します
void setRecord(struct Record* pR, char* str) {
int i = 0;
// 最初の","を探す
char* pStr = strtok(&str[1], "\",\"");
while (pStr) {
switch (i) {
case 0:
// インデックス
pR->idx = atoi(pStr);
break;
case 1:
// タイトル
strcpy(pR->title, pStr);
break;
case 2:
// 日付
strcpy(pR->date, pStr);
break;
default:
break;
}
i++;
// ","を探す
pStr = strtok(NULL, "\",\"");
if (pStr == NULL ) {
// ","がない場合、最後の"を探す
pStr = strtok(NULL, "\"\n");
}
}
}
// ポイント2.3 Record構造体比較関数を作ります。
// Record構造体比較関数
// qsortから呼び出され、比較結果を返す事でソートを実現します。
int compRecord(const void * p1, const void * p2) {
struct Record *r1 = *((struct Record **)p1);
struct Record *r2 = *((struct Record **)p2);
// 文字列比較
// ポイント2.2 構造体に入れたので好きな項目でソートできます
int cmp = strcmp(r1->date, r2->date);
if (cmp != 0) {
// 日付が違う場合、strcmpの結果をそのまま返します
return cmp;
}
// 日付が同じ場合、インデックスを比較します
if(r1->idx > r2->idx) {
return 1;
} else if (r1->idx < r2->idx) {
return -1;
}
// インデックスも同じ場合0を返します
return 0;
}
// CSVファイル出力
void output(FILE* fp, struct Record** out, int size) {
int i;
printf("sort後\n");
for (i = 0; i < size; i++) {
// ポイント3 カンマ区切りの文字列を作成して出力します
fprintf(fp, "\"%d\",\"%s\",\"%s\"\n", out[i]->idx, out[i]->title,
out[i]->date);
printf("\"%d\",\"%s\",\"%s\"\n", out[i]->idx, out[i]->title,
out[i]->date);
}
}
int main(int argc, char *argv[]) {
char str[255];
// 構造体の配列
struct Record record[100];
// 構造体のポインタの配列(ソート用)
struct Record *sorted[100];
int i = 0, size;
// fopen(ファイル名, オプション)でファイルを開きます
FILE* fpr = fopen(argv[1], "r");
FILE* fpw = fopen(argv[2], "w");
// ファイルを開けない場合、FILEのポインタがNULLになります
if (fpr == NULL || fpw == NULL) {
puts("ファイルが開けないよ!");
return EXIT_FAILURE;
}
printf("sort前\n");
// fgets(読み込むバッファ, バッファのサイズ, FILEのポインタ)で一行ずつ読み込みます
while (fgets(str, 255, fpr)) {
// 読み込んだ内容をそのまま出力
printf(str);
// ポイント1 読み込んだテキストを、分解して構造体の配列に設定します。
// Record構造体にデータを設定
setRecord(&record[i], str);
i++;
}
// サイズを保存
size = i;
// 出力用ポインタ配列にRecordのポインタをすべて設定する
for (i = 0; i < size; i++) {
sorted[i] = &record[i];
}
// ポイント2 構造体の配列をソートします
// qsortのパラメータは1.ソートするデータの配列 2.ソートするデータの個数 3.データ一個あたりのサイズ 4.比較関数のポインタ
qsort(sorted, size, sizeof(sorted[0]), compRecord);
// 出力ファイルに書き込みます
output(fpw, sorted, size);
// ファイルをクローズ
fclose(fpr);
fclose(fpw);
return EXIT_SUCCESS;
}
}}
* 読み込ませたCSVファイル &ref(sort.csv)
"1","CSV読込ソート出力の","2011/01/01"
"2","テスト中","2012/10/01"
"3","読み込めてますかー","2010/09/10"
"4","もっと行を","2011/01/01"
"5","増やしてみましょう","2012/10/01"
"6","これぐらいかな?","2010/09/10"
* 実行結果
&ref(CSVファイルの読込ソート出力2.png)
* サンプルダウンロード
サンプルソース &ref(sortCsv2.c)
読み込ませたCSV &ref(sort.csv)
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[8]","役に立たない[0]","分かりにくい[4]","間違っている[0]","...[1]",""の条件が足りない[1]","うざい[20]","楽しい[1]","にょ[2]")
2024-02-29T13:18:08+09:00
1709180288
-
C言語/サンプル/構造体をファイルに読み書き
https://w.atwiki.jp/chapati4it/pages/113.html
C言語では、アプリの終了、再開時にデータを簡単に保存、再利用する方法として、
構造体をまるごとファイルに出力して、アプリの再開時にまるっと読み込むという、定番のテクニックがあります。
出力されたファイルは、CSVファイルと比べると人間の目には優しくないですが、
なんと言っても簡単ですし、バイナリエディタで見ればなんとか読めない事もありません。
* ■目次
#contents(fromhere=true)
* 1.構造体をファイルに出力する
#highlight(c){{
// 構造体出力
// 1.バイナリモードで出力ファイルオープン
FILE *fpw = fopen("struct.dat", "wb");
// 2.構造体1個分出力
fwrite(&wStruct, sizeof(wStruct), 1, fpw);
// 3.出力ファイルクローズ
fclose(fpw);
}}
+ fopenでバイナリの書き込みモードでファイルを開きます。
+ writeで構造体の先頭アドレスから、構造体のサイズ分だけ出力します。
+ 出力ファイルをクローズします。
* 2.ファイルから構造体に読み込む
#highlight(c){{
// 構造体読込
// 1.バイナリモードで読込ファイルオープン
FILE *fpr = fopen("struct.dat", "rb");
// 2.構造体1個分読込
fread(&rStruct, sizeof(rStruct), 1, fpr);
// 3.読込ファイルクローズ
fclose(fpr);
}}
+ fopenでバイナリの読み込みモードでファイルを開きます。
+ read関数で構造体の先頭アドレスから、構造体のサイズ分だけファイルを読み込みます。
+ 読込ファイルをクローズします。
+ 読込は、出力の手順からfopenのパラメータと、「fwrite」が「fread」に変わるだけです。
* 3.サンプル
構造体を作成し、ファイルに書込、書き込んだファイルを読み込んで標準出力に読み込んだ結果を出力します。
#highlight(c){{
#include <stdio.h>
#include <stdlib.h>
// テスト用構造体
struct Syain {
long id;
char name[20];
int age;
char tell[14];
char email[20];
};
int main(void) {
// 構造体作成
struct Syain rStruct;
struct Syain wStruct = { 2001, "新入社員A", 22, "000-0000-0000",
"newsyain@example.com" };
// 構造体出力
// 1.バイナリモードで出力ファイルオープン
FILE *fpw = fopen("struct.dat", "wb");
// 2.構造体1個分出力
fwrite(&wStruct, sizeof(wStruct), 1, fpw);
// 3.出力ファイルクローズ
fclose(fpw);
// 構造体読込
// 1.バイナリモードで読込ファイルオープン
FILE *fpr = fopen("struct.dat", "rb");
// 2.構造体1個分読込
fread(&rStruct, sizeof(rStruct), 1, fpr);
// 3.読込ファイルクローズ
fclose(fpr);
// 読み込んだ構造体を標準出力に書き出し
printf("id = %ld\n", rStruct.id);
printf("name = %s\n", rStruct.name);
printf("age = %d\n", rStruct.age);
printf("tell = %s\n", rStruct.tell);
printf("email = %s\n", rStruct.email);
return EXIT_SUCCESS;
}
}}
** 3b.サンプル実行結果
#highlight(){{
id = 2001
name = 新入社員A
age = 22
tell = 000-0000-0000
email = newsyain@example.com
}}
** 3c.サンプルダウンロード
サンプルソース &ref(cstructIO.c)
構造体の出力結果 &ref(struct.dat)
* 4.構造体の配列を読み書きする場合のサンプル
#highlight(c){{
#include <stdio.h>
#include <stdlib.h>
// テスト用構造体
struct Syain {
long id;
char name[20];
int age;
char tell[14];
char email[20];
};
int main(void) {
// 構造体作成
// ★変更点1 構造体を構造体の配列に変更★
struct Syain rStruct[2];
struct Syain wStruct[] = {
{ 2001, "新入社員A", 22, "000-0000-0000", "newsyain@example.com" },
{ 2002, "新入社員B", 23, "001-0001-0001", "newsyain2@example.com" }
};
// 構造体出力
// 1.バイナリモードで出力ファイルオープン
FILE *fpw = fopen("struct.dat", "wb");
// 2.構造体の配列出力
fwrite(&wStruct, sizeof(wStruct), 1, fpw);
// 3.出力ファイルクローズ
fclose(fpw);
// 構造体読込
// 1.バイナリモードで読込ファイルオープン
FILE *fpr = fopen("struct.dat", "rb");
// 2.構造体の配列に読込
fread(&rStruct, sizeof(rStruct), 1, fpr);
// 3.読込ファイルクローズ
fclose(fpr);
// 読み込んだ構造体を標準出力に書き出し
printf("id = %ld\n", rStruct[0].id);
printf("name = %s\n", rStruct[0].name);
printf("age = %d\n", rStruct[0].age);
printf("tell = %s\n", rStruct[0].tell);
printf("email = %s\n", rStruct[0].email);
// ★変更点2 構造体の内容出力★
printf("id = %ld\n", rStruct[1].id);
printf("name = %s\n", rStruct[1].name);
printf("age = %d\n", rStruct[1].age);
printf("tell = %s\n", rStruct[1].tell);
printf("email = %s\n", rStruct[1].email);
return EXIT_SUCCESS;
}
}}
- 構造体の配列を読み書きする場合も特に難しい事はありません。
- sizeof(構造体の配列)で、構造体の配列全体のサイズを取得できるので、読み込みも書き込みも特に修正は不要です。
* 要注意!
・ポインタ変数を含む構造体の入出力には気をつけてください。
・ポインタを含む構造体を出力して、次に読み込んだ時、そのポインタは利用できないので初期化する必要があります。
・出来ればポインタ変数のない構造体を入出力してください。
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[107]","役に立たない[9]","分かりにくい[17]","間違っている[9]","うざい[9]","かわいい[25]","眠い[19]","しこりたい[24]","うんち[23]","もう少し改善して、どうぞ[10]")
2024-02-21T15:06:39+09:00
1708495599
-
Java/Tomcat/ファイルをアップロードするサンプル(Commons FileUplaod)
https://w.atwiki.jp/chapati4it/pages/154.html
Tomcat7でアップロードされたファイルを取得するには、Commons FileUploadを利用します。
Commons FileUploadを利用しない場合、かなり面倒なプログラムを組む必要があると思いますが、Commons FileUploadを使えばかなり簡単にアップロードしたファイルを取得出来ます。
* ■目次
#contents(fromhere=true)
*前提条件
Tomcat7
JDK1.6
Commons FileUpload 1.3
Commons IO 2.4
* ライブラリの準備
** Commons FileUpload
- http://commons.apache.org/proper/commons-fileupload/
Commons FileUploadを上記のアドレスからダウンロードします。
今回は「commons-fileupload-1.3-bin.zip」をダウンロードしました。
ダウンロード出来たら「commons-fileupload-1.3-bin.zip」の中から「commons-fileupload-1.3.jar」を取り出し、プロジェクトの「/WEB-INF/lib」ディレクトリに配置します。
eclipse等IDEでも「commons-fileupload-1.3.jar」をビルドパスに追加しましょう。
追加しないとコンパイルエラーが出ます。
** Commons IO
- http://commons.apache.org/proper/commons-io/
Commons IOも上記のアドレスからダウンロードしましょう。
今回は「commons-io-2.4-bin.zip」をダウンロードしました。
ダウンロード出来たら「commons-io-2.4-bin.zip」の中から「commons-io-2.4.jar」を取り出し、プロジェクトの「/WEB-INF/lib」ディレクトリに配置します。
こちらはIDEのビルドパスに追加しなくても大丈夫です。Commons FileUploadが内部的に使っているからコンパイルするだけなら不要なのです。
* サンプルアプリ
** &ref(web.xml)の設定
#highlight(){{
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- サーブレットの宣言 -->
<servlet>
<servlet-name>FileUploadSample</servlet-name>
<servlet-class>FileUploadSample</servlet-class>
</servlet>
<!-- サーブレットとurlのマッピング -->
<servlet-mapping>
<servlet-name>FileUploadSample</servlet-name>
<url-pattern>/up</url-pattern>
</servlet-mapping>
</web-app>
}}
- web.xmlは特に代わり映えはしません。
** サンプルJSP &ref(index.jsp)
#highlight(){{
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>[Tomcat] ファイルアップロードサンプル。</title>
</head>
<body>
<h1>[Tomcat] ファイルアップロードサンプル。</h1>
<form method="POST" enctype="multipart/form-data" action="up">
ファイル : <input type="file" name="upfile"><br/>
メモ : <input type="text" name="note"><br/>
<br/>
<input type="submit" value="Press"> ファイルをアップロードします!
</form>
</body>
</html>
}}
- ファイルをアップロードする時は、formタグのメソッドを「POST」、enctypeを「multipart/form-data」にします。
- JSPファイルになっていますが、JSPである必要性のないJSPファイルになってしまいました。
** サンプルサーブレット &ref(FileUploadSample.java)
#highlight(){{
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* [Tomcat] ファイルアップロードサンプル。
*/
public class FileUploadSample extends HttpServlet {
// (1) ファイルアップロードする時は、doPostメソッドを使います。
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// (2) アップロードファイルを受け取る準備
// ディスク領域を利用するアイテムファクトリーを作成
DiskFileItemFactory factory = new DiskFileItemFactory();
// tempディレクトリをアイテムファクトリーの一次領域に設定
ServletContext servletContext = this.getServletConfig().getServletContext();
factory.setRepository((File) servletContext.getAttribute("javax.servlet.context.tempdir"));
// ServletFileUploadを作成
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// (3) リクエストをファイルアイテムのリストに変換
List<FileItem> items = upload.parseRequest(request);
// アップロードパス取得
String upPath = servletContext.getRealPath("/") + "upload/";
byte[] buff = new byte[1024];
int size = 0;
for (FileItem item : items) {
// (4) アップロードファイルの処理
if (!item.isFormField()) {
// ファイルをuploadディレクトリに保存
BufferedInputStream in = new BufferedInputStream(item.getInputStream());
File f = new File(upPath + item.getName());
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(f));
while ((size = in.read(buff)) > 0) {
out.write(buff, 0, size);
}
out.close();
in.close();
// アップロードしたファイルへのリンクを表示
response.getWriter().print("<a href='");
response.getWriter().print(servletContext.getContextPath() + "/upload/" + item.getName());
response.getWriter().print("'>" + item.getName() + "</a>");
// (5) フォームフィールド(ファイル以外)の処理
} else {
// ここでは処理せず、直接requestからgetParamしてもいいと思います。
}
}
} catch (FileUploadException e) {
// 例外処理
}
response.getWriter().flush();
}
}
}}
*** サンプルサーブレットのポイント
- 1.ファイルアップロードする時は、doPostメソッドを使います。
-- htmlの方でメソッドを「POST」にした場合、Servletで受け取る時は「doPost」になります。
- 2.アップロードファイルを受け取る準備
-- 特に説明することもないと思います。
-- オブジェクト作ったり、ファイルの一時領域を設定してます。
- 3.リクエストをファイルアイテムのリストに変換
-- List<FileItem> items = upload.parseRequest(request);
--- ここでリクエストをファイルアイテムのリストに変換しています。
- 4.アップロードファイルの処理
-- ここでは、アップロードされたファイルやパラメータの処理を行います。
-- 「FileItem.isFormField()」このメソッドでfalseが返って来たらファイルだと思っていいです。
--- trueだったら、ファイル以外のフォームフィールドです。
-- 今回行なっているのは、アップロードされたファイルを「/upload/~」にコピーして、コピー先へのリンクを表示する処理です。
- 5.フォームフィールド(ファイル以外)の処理
-- ここでは、ファイル以外のフィールドの処理を記述します。
-- 今回は、「フィールド名 : 値」を表示するだけの簡単な処理にしてあります。
* サンプルダウンロード
&ref(web.xml)
&ref(index.jsp)
&ref(FileUploadSample.java)
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[51]","役に立たない[8]","分かりにくい[12]","間違っている[4]","ありがとう[22]","今日の晩飯は、カレー[136]","はらへった[16]","3[3]","お腹の肉が気になる[22]","私は神だ!!![13]","227[3]","<script></script>[2]","https://w.atwiki.jp/chapati4it/pages/154.html[1]","わかりやすかったですが、ソースコード箇所のファストビューの情報量を増やしてもらえるともっとみやすかったです。[2]")
2024-01-23T14:15:00+09:00
1705986900
-
Java/Tomcat/JFreeChartで動的にグラフを出力するサンプル
https://w.atwiki.jp/chapati4it/pages/153.html
JFreeChartを使って、グラフを出力するサーブレットと、ウェブページにグラフを表示するサンプルです。
JFreeChartはJava用のグラフを出力するライブラリです。
* ■目次
#contents(fromhere=true)
* JFreeChartのセットアップ
** ダウンロード
- http://www.jfree.org/index.html
JFreeChartのサイトでぽちぽちクリックしていると、SourceForgeに移動しました。
- http://sourceforge.net/projects/jfreechart/files/
さらに「JFreeChart」のリンクをクリックすると色んなバージョンの番号が見えます。
今回は「1.0.14」を選んでみました。
- http://sourceforge.net/projects/jfreechart/files/1.%20JFreeChart/1.0.14/
zipファイルと、tar.gzファイルが選べたので今回は「jfreechart-1.0.14.zip」をダウンロードしました。
** インストール
1.ダウンロードしたファイルから、以下の2ファイルを取り出します。
>jcommon-1.0.17.jar
>jfreechart-1.0.14.jar
2.Tomcatプロジェクトの「/WEB-INF/lib」ディレクトリに上記のファイルをコピーします。
Tomcatは「/WEB-INF/lib」ディレクトリに配置したjarファイルをアプリケーションから利用出来るので、これだけでJFreeChartを利用する準備完了です。
** eclipseの設定
Tomcatのための設定は「/WEB-INF/lib」にjarファイルを配置すれば完了ですが、eclipseでもクラスパスにjarファイルを入れて上げないとコンパイルエラーが出て大変です。
eclipseのための設定は、eclipseから「/WEB-INF/lib」にコピーしたjarファイルを選択し、右クリックメニューから「ビルドパス→ビルドパスに追加」を選択すれば完了です。
これで、eclipseでJFreeChartアプリを開発出来る準備が整いました。
* サンプルアプリケーション
** サンプルサーブレット &ref(JFreeChartSample.java)
#highlight(java){{
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
/**
* [Tomcat] JFreeChartで動的にグラフを出力するサンプル。
*/
public class JFreeChartSample extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// コンテンツタイプ設定
response.setContentType("image/png");
// 円グラフのデータ作成
DefaultPieDataset data = new DefaultPieDataset();
data.setValue("いちご", 1500);
data.setValue("オレンジ", 1500);
data.setValue("バナナ", 5000);
// JFreeChartオブジェクト作成
JFreeChart chart = new JFreeChart(new PiePlot(data));
// 円グラフ出力
ChartUtilities.writeChartAsPNG(response.getOutputStream(), chart, 200, 200);
// アウトプットストリームをフラッシュ
response.getOutputStream().flush();
}
}
}}
- 簡単な円グラフを出力するサーブレットなら簡単に出来ます。
- ポイントは2つで、1つは以下のコンテンツタイプ設定。
>// コンテンツタイプ設定
>response.setContentType("image/png");
コンテンツタイプを設定するとブラウザが「画像なんだな」とスムーズに判断してくれます。
- もう1つは、以下の円グラフ出力に使っているメソッド。
>// 円グラフ出力
>ChartUtilities.writeChartAsPNG(response.getOutputStream(), chart, 200, 200);
この「writeChartAsPNG」を使うことで、レスポンスのアウトプットストリームにpngのイメージを出力しています。
一次的にファイルに保存する必要がないので便利です。
※「saveChartAsPNG」を使うと、「pngファイル」を実際のファイルに出力スルことができます。
** &ref(web.xml)
#highlight(){{
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- サーブレットの宣言 -->
<servlet>
<servlet-name>JFreeChartSample</servlet-name>
<servlet-class>JFreeChartSample</servlet-class>
</servlet>
<!-- サーブレットとurlのマッピング -->
<servlet-mapping>
<servlet-name>JFreeChartSample</servlet-name>
<url-pattern>/chart/piechart.png</url-pattern>
</servlet-mapping>
</web-app>
}}
- サーブレットのマッピングで、以下のように<url-pattern>に画像ファイル名を入れておくと、グラフを保存したい人に便利です。
><url-pattern>/chart/piechart.png</url-pattern>
- 画像ファイルの部分をワイルドカードにして、ファイル名をhtml側で自由に決めさせるのもいいでしょう。
><url-pattern>/chart/*</url-pattern>
* 動作確認
「http://localhost:8080/jfc/chart/piechart.png」にアクセスして以下の様なグラフが表示されれば成功です。
※「jfc」の部分にはコンテキストを設定してください。
&ref(piechart.png)
* サンプルアプリケーションその2 ウェブページ(jsp)にグラフを表示する
上記のサンプルでは、グラフ作成サーブレットのアドレスを直接叩いてグラフを表示しましたが、通常はウェブページの中に埋め込んで利用する方が多いと思います。
ウェブページにJFreeChartで作成したグラフを表示させるには、上記で動作確認に利用したアドレス「http://localhost:8080/jfc/chart/piechart.png」を表示するhtmlを作成します。
** サンプルJSP &ref(index.jsp)
#highlight(){{
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>[Tomcat] ウェブページにJFreeChartで動的に生成したグラフを表示する。</title>
</head>
<body>
<h1>[Tomcat] ウェブページにJFreeChartで動的に生成したグラフを表示する。</h1>
<img src='<%=request.getContextPath()%>/chart/piechart.png'>
<p>ウェブページにJFreeChartで動的に生成したグラフを表示するサンプルです。 </p>
</body>
</html>
}}
- サンプルJSPの肝は、以下のimgタグです。
><img src='<%=request.getContextPath()%>/chart/piechart.png'>
- imgタグの属性srcに、先ほど作成したグラフ作成サーブレットのアドレスを設定する事で、グラフ作成サーブレットにリクエストが飛んで、ウェブページの中に動的に生成したグラフが表示されます。
** 動作確認
「http://localhost:8080/jfc/」にアクセスして以下の様なグラフが表示されれば成功です。
※「jfc」の部分にはコンテキストを設定してください。
&ref(piechart02.png)
* サンプルダウンロード
- &ref(JFreeChartSample.java)
- &ref(web.xml)
- &ref(index.jsp)
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[26]","役に立たない[6]","分かりにくい[5]","間違っている[1]")
2024-01-23T14:06:41+09:00
1705986401
-
Java/swing/サンプル/画像表示(拡大縮小)
https://w.atwiki.jp/chapati4it/pages/21.html
Javaのswingで画像を拡大縮小して表示するサンプルです。
* ポイント
+ ImageIconクラスでアイコンとして画像を読み込みます。
+ getScaledInstanceで大きさを変更します。
++ 幅と高さともに同じ倍率にする場合、高さは-1にしてもいいです。
+ MediaTrackerで処理の終了を待ちます。
++ 画像の加工は、加工完了する前に処理が戻ってくるので、waitForAll()などで処理の終了を待機する必要がある…らしいです。
+ JLabelにアイコンを設定します。
大きさを変更するのも意外と簡単です。
* 実行結果
&ref(swing 画像表示サンプル2.png)
* ソース &ref(ImageTest2.java)
#highlight(java) {{
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSeparator;
// swing 画像表示サンプル2 画像を拡大縮小してみよう
// ポイント1.ImageIconクラスでアイコンとして画像を読み込みます。
// ポイント2.getScaledInstanceで大きさを変更します。
// 幅と高さともに同じ倍率にする場合、高さは-1にしてもいいです。
//
// ポイント3.MediaTrackerで処理の終了を待ちます。
// 画像の加工は、加工完了する前に処理が戻ってくるので、waitForAll()などで処理の終了を待機する必要がある…らしいです。
// ポイント4.JLabelにアイコンを設定します。
// 大きさを変更するのも意外と簡単です。
public class ImageTest2 extends JFrame {
public static void main(String[] args) {
new ImageTest2();
}
public ImageTest2() {
setTitle("swing 画像表示サンプル2 画像を拡大縮小してみよう");
// 今回はレイアウトマネージャを使います
setLayout(new FlowLayout());
// ポイント1.ImageIconクラスでアイコンとして画像を読み込みます。
ImageIcon icon = new ImageIcon("logo3w.png");
MediaTracker tracker = new MediaTracker(this);
// ポイント2.getScaledInstanceで大きさを変更します。
Image smallImg = icon.getImage().getScaledInstance((int) (icon.getIconWidth() * 0.5), -1,
Image.SCALE_SMOOTH);
Image bigImg = icon.getImage().getScaledInstance((int) (icon.getIconWidth() * 1.5), -1,
Image.SCALE_SMOOTH);
// ポイント3.MediaTrackerで処理の終了を待ちます。
tracker.addImage(smallImg, 1);
tracker.addImage(bigImg, 2);
ImageIcon smallIcon = new ImageIcon(smallImg);
ImageIcon bigIcon = new ImageIcon(bigImg);
try {
tracker.waitForAll();
} catch (InterruptedException e) {
System.out.println("なんかエラーでた。");
}
// ポイント4.JLabelにアイコンを設定します。
JLabel l = new JLabel("0.5", smallIcon, JLabel.LEFT);
JLabel ll = new JLabel("1.0", icon, JLabel.LEFT);
JLabel lll = new JLabel("1.5", bigIcon, JLabel.LEFT);
// 関係ないポイント
// 横幅の大きなJseparatorを差し込むと、JFlowLayoutの強制改行みたいな事ができます
JSeparator sp = new JSeparator();
JSeparator sp2 = new JSeparator();
sp.setPreferredSize(new Dimension(5000, 0));
sp2.setPreferredSize(new Dimension(5000, 0));
add(l);
add(sp);
add(ll);
add(sp2);
add(lll);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(100, 100, 500, 350);
setVisible(true);
}
}
}}
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[64]","役に立たない[15]","分かりにくい[25]","間違っている[0]")
2023-12-29T09:45:04+09:00
1703810704
-
コメント/Java/swing/サンプル/JButton ボタンをクリックしたらメッセージを表示するサンプル
https://w.atwiki.jp/chapati4it/pages/589.html
-mm - mm (2023-01-17 18:29:14)
2023-01-17T18:29:14+09:00
1673947754
-
Java/swing/サンプル/メニュー、タイトルバー、ステータスバー、ツールバーの表示on off切り替えサンプル
https://w.atwiki.jp/chapati4it/pages/156.html
メニュー、タイトルバー、ステータスバー、ツールバーの表示切り替えを、「ショートカットキー」「メニュー」「ツールバー」から行うサンプルです。
* ■目次
#contents(fromhere=true)
* サンプルソース &ref(MenuOnOfSample.java)
#highlight(){{
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;
/**
* メニューの表示・非表示サンプル
* Ctrl + A : メニューの表示切り替え
* Ctrl + B : タイトルバー
* Ctrl + C : ステータスバー
* Ctrl + D : ツールバー
* ショートカットキーとメニュー、ツールバーからそれぞれ切り替えサンプル
*/
public class MenuOnOfSample extends JFrame {
// メニュー
JMenuBar menuBar = new JMenuBar();
// ステータスバー
JPanel statusBar = new JPanel();
// ツールバー
JToolBar toolBar = new JToolBar();
public static void main(String[] args) {
new MenuOnOfSample();
}
public MenuOnOfSample() {
initUI();
}
/**
* ユーザーインターフェース作成
*/
private void initUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("メニューの表示切り替え");
setBounds(100, 100, 300, 200);
// メニュー作成
createMenu();
// ステータスバー作成
createStatusBar();
// ツールバー作成
createToolBar();
// ショートカットキーのためにリスナー追加
addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
doKeyEvent(e);
}
});
// テキストエリア追加
JTextArea textArea = new JTextArea();
// テキストエリアにもキーボードイベントを処理するようにリスナーを追加します
// これを入れないとテキストエリアにフォーカスがある時に、表示切り替えができません
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
doKeyEvent(e);
}
});
add(textArea, BorderLayout.CENTER);
setVisible(true);
}
/**
* ステータスバー作成
*/
private void createStatusBar() {
statusBar.setBorder(new BevelBorder(BevelBorder.LOWERED));
statusBar.setPreferredSize(new Dimension(this.getWidth(), 16));
statusBar.setLayout(new BoxLayout(statusBar, BoxLayout.X_AXIS));
JLabel label = new JLabel("status bar");
statusBar.add(label);
add(statusBar, BorderLayout.SOUTH);
}
/**
* メニュー作成
*/
private void createMenu() {
// メニュー作成
JMenu menu = new JMenu("表示(M)");
// メニューアイテム作成
JMenuItem item1 = new JMenuItem("メニューの表示切り替え(A)");
JMenuItem item2 = new JMenuItem("タイトルバーの表示切り替え(B)");
JMenuItem item3 = new JMenuItem("ステータスバーの表示切り替え(C)");
JMenuItem item4 = new JMenuItem("ツールバーの表示切り替え(D)");
// メニューアイテムにアクションリスナー追加
item1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchMenuBar();
}
});
item2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchTitleBar();
}
});
item3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchStatusBar();
}
});
item4.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchToolBar();
}
});
// メニューにメニューアイテム追加
menu.add(item1);
menu.add(item2);
menu.add(item3);
menu.add(item4);
// メニューバーにメニューを追加
menuBar.add(menu);
// フレームにメニューバーを追加
setJMenuBar(menuBar);
}
/**
* ツールバー作成
*/
public void createToolBar() {
// ボタン作成
JButton button1 = new JButton("M");
JButton button2 = new JButton("Ti");
JButton button3 = new JButton("S");
JButton button4 = new JButton("To");
// ボタンにアクションリスナー追加
button1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchMenuBar();
}
});
button2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchTitleBar();
}
});
button3.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchStatusBar();
}
});
button4.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchToolBar();
}
});
// ツールチップ設定
button1.setToolTipText("メニューの表示/非表示を切り替えます。");
button2.setToolTipText("タイトルバーの表示/非表示を切り替えます。");
button3.setToolTipText("ステータスバーの表示/非表示を切り替えます。");
button4.setToolTipText("ツールバーの表示/非表示を切り替えます。");
// ツールバーにボタン追加
toolBar.add(button1);
toolBar.add(button2);
toolBar.add(button3);
toolBar.add(button4);
// 画面下部にツールバー追加
add(toolBar, BorderLayout.NORTH);
}
/**
* キーイベント
*
* @param e
*/
public void doKeyEvent(KeyEvent e) {
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) > 0) {
// Ctrl + A 判定
if (e.getKeyCode() == KeyEvent.VK_A) {
// メニューバー表示切り替え
switchMenuBar();
}
// Ctrl + B 判定
if (e.getKeyCode() == KeyEvent.VK_B) {
// タイトルバー表示切り替え
switchTitleBar();
}
// Ctrl + C 判定
if (e.getKeyCode() == KeyEvent.VK_C) {
// ステータスバー表示切り替え
switchStatusBar();
}
// Ctrl + D 判定
if (e.getKeyCode() == KeyEvent.VK_D) {
// ツールバー表示切り替え
switchToolBar();
}
}
}
/**
* メニューバー表示切り替え
*/
public void switchMenuBar() {
menuBar.setVisible(!menuBar.isVisible());
}
/**
* ステータスバー表示切り替え
*/
public void switchStatusBar() {
statusBar.setVisible(!statusBar.isVisible());
}
/**
* タイトルバー表示切り替え
*/
public void switchTitleBar() {
dispose();
setUndecorated(!isUndecorated());
setVisible(true);
}
/**
* ツールバー表示切り替え
*/
public void switchToolBar() {
toolBar.setVisible(!toolBar.isVisible());
}
}
}}
* ポイント解説
** メニュー、ステータスバー、ツールバーの表示切り替え
>menuBar.setVisible(!menuBar.isVisible());
>statusBar.setVisible(!statusBar.isVisible());
>toolBar.setVisible(!toolBar.isVisible());
- 上記のコードは呼び出される度に、表示/非表示を切り替えます。
--「isVisible」に!を付けて「setVisible」することで、呼び出す度に簡単に表示/非表示が切り替わるのです。
** タイトルバーの表示切り替え
>dispose();
>setUndecorated(!isUndecorated());
>setVisible(true);
- タイトルバーの表示切り替えには「setUndecorated」を使います。
-- メニューの表示切り替えと同じく、「isUndecorated」に!を付けて切り替えています。
-「setUndecorated」はフレームが表示されていない時に呼び出す必要があるので、事前に「dispose」でリソースを破棄します。
-- 「setUndecorated」が終わったら、「setVisible(true)」でフレームを再表示しています。
** キーボードショートカット
- メニューアイテムに「setAccelerator」でショートカットキーを設定することも出来るのですが、この場合メニューを非表示にするとショートカットキーが効かなくなります。
- 今回のサンプルはメニューの表示切り替えなので、自力でキーボードショートカットを処理しています。
#highlight(){{
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) > 0) {
// Ctrl + A 判定
if (e.getKeyCode() == KeyEvent.VK_A) {
// メニューバー表示切り替え
switchMenuBar();
}
}}
- 上記のサンプルは、まず「if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) > 0)」でCtrlキーの同時押しを判定しています。
-- Altキーなら「InputEvent.ALT_DOWN_MASK」、Shiftキーなら「InputEvent.SHIFT_DOWN_MASK」で判定できます。
- 次に「if (e.getKeyCode() == KeyEvent.VK_A)」で「A」が押されているか判定しています。
** テキストエリアでショートカットキーを押した時の処理
#highlight(){{
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
doKeyEvent(e);
}
});
}}
- JFrameにショートカットキーのリスナーを追加しても、JTextArea等のコンポーネントにフォーカスが行くと、JFrameのリスナーまでイベントが届かず、ショートカットキーを押しても何も起きなくなってしまいます。
- そんなコンポーネントを追加した時は、それぞれのコンポーネントに「addKeyListener」でリスナーを追加してあげましょう。
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[6]","役に立たない[2]","分かりにくい[2]","間違っている[1]")
2022-09-18T10:17:51+09:00
1663463871
-
コメント/Java/帳票/JasperReports5.0 PDFに動的に画像を埋め込み
https://w.atwiki.jp/chapati4it/pages/517.html
-えふぁd - てtst 2013-12-09 16:13:29
-えr - dfg (2022-04-11 12:06:57)
2022-04-11T12:06:57+09:00
1649646417
-
Java/Tomcat/Basic認証(UserDatabaseRealm)+DIGEST認証
https://w.atwiki.jp/chapati4it/pages/145.html
TomcatのBasic認証を使って、「管理画面、会員用コンテンツ、公開コンテンツ」の三段階のアクセス管理を設定してみましょう。
※ちょっと設定を変えると&link_anchor(digest){DIGEST認証}にもなるよ。
* ■目次
#contents(fromhere=true)
* ポイント
- Basic認証を利用するには、まず「&link_anchor(web.xml){web.xml}」で認証方式とアクセス制御を設定するURLと権限の設定をします。
- その上で、認証するユーザー、ロール(役割、権限)の設定をTomcatに指定するために以下の設定が必要になります。
-- 「&link_anchor(server.xml){server.xml}」でレルム(認証情報の取り扱い方法)の設定
--- 今回利用する「UserDatabeseRealm」はTomcatインストール時のデフォルト設定なので、設定を変更していななければ「server.xml」は編集する必要はありません。
-- 「&link_anchor(tomcat-users.xml){tomcat-users.xml}」でユーザーとロールの設定
* web.xml
#highlight(){{
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 管理画面の定義 -->
<security-constraint>
<!-- URLのパターン設定 -->
<web-resource-collection>
<web-resource-name>admin page</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<!-- アクセスを許可するロールの設定 -->
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<!-- 通信方式 NONE=ノーガード INTEGRAL=改竄防止(https) CONFIDENTIAL=盗聴防止(https) -->
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- 会員用コンテンツの定義 -->
<security-constraint>
<web-resource-collection>
<web-resource-name>users page</web-resource-name>
<url-pattern>/users/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- 認証方法の定義 -->
<login-config>
<!-- Basic認証 -->
<auth-method>BASIC</auth-method>
<!-- 認証ダイアログに表示されるエリア名的な何か -->
<realm-name>security area</realm-name>
</login-config>
</web-app>
}}
- 今回はサーブレットを作成していないので、認証設定だけのweb.xmlです。
- web.xmlでは主に、サーバクライアント間の認証方法と、アクセス制御するURLとロールの設定を行います。
- <security-constraint>で、URLのパターン設定(複数可)、アクセスを許可するロールの設定(複数可)、通信方式の設定をしています。
-- 「/admin/*」で、adminディレクトリ配下全てがアクセス制御の対象となります。
-- httpsの設定は今回行なっていないので、通信方式はNONEを選択しました。
- <login-config>で、認証方法とダイアログに表示されるエリア名を設定しています。
-- なんか微妙です。
** web.xml DIGEST認証の場合
#highlight(){{
<!-- 認証方法の定義 -->
<login-config>
<!-- DIGEST認証 -->
<auth-method>DIGEST</auth-method>
<!-- 認証ダイアログに表示されるエリア名的な何か -->
<realm-name>security area</realm-name>
</login-config>
}}
- 上記web.xmlの設定の<login-config><auth-method>をDIGESTに変更するだけで、DIGEST認証を利用出来ます。
-- Tomcat7はここを変えるだけで利用出来ますが、Tomcat5はレルム方式をメモリレルムにしないとDIGEST認証を利用出来ないそうです。
* server.xmlの設定
(認証に関係のある要素を抜粋)※デフォルトなら編集不要
#highlight(){{
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<!-- JNDIリソースの設定 conf/tomcat-users.xmlを認証情報に利用します -->
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Engine name="Catalina" defaultHost="localhost">
<!-- ブルートフォースアタック対策にLockOutRealmでラップします -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- 認証に利用するクラスとリソースを設定 -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
</Engine>
</Service>
</Server>
}}
- server.xmlでは主に、サーバ内での認証情報(リソース)の取り扱いを設定します。
- 上記の設定はTomcat7インストール時のデフォルト設定です。
-- デフォルトでUserDatabaseRealmを利用する場合、server.xmlは編集不要です。
- 前段で「conf/tomcat-users.xml」からログインIDやパスワード等の認証に必要な情報を読取るJNDIリソースの設定。
- 後段で、リソースの指定と認証に使うクラスの指定に分かれています。
- ブルートフォースアタック対策のUserDatabaseRealmをブルートフォースアタック対策のLockOutRealmでラッピングしているのが印象的な設定です。
* tomcat-users.xml
#highlight(){{
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="admin"/>
<role rolename="user"/>
<user username="admin" password="password1" roles="admin,user"/>
<user username="user1" password="password2" roles="user"/>
</tomcat-users>
}}
- ロールは管理者用のadminロールと、会員用のuserロールを作成します。
- adminユーザーはadminロールとuserロール両方を設定。
- user1ユーザーはuserロールのみ設定します。
- 管理者を増やす時は、adminユーザーの設定をコピーしてusernameとpasswordをそれぞれ設定します。
- ユーザーを増やす時も同様に、user1ユーザーの設定をコピーしてusernameとpasswordをそれぞれ設定します。
* index.jsp サンプルダウンロード
&ref(BasicAuth.zip)
- サンプルをダウンロードして見てみてください。
&ref(BasicAuth01.png)
Tomcatを起動してブラウザでusersディレクトリやadminディレクトリにアクセスすると、上のようなユーザー名とパスワードの入力を求めるダイアログが表示されます。
user1でログインしてadminディレクトリにアクセスすると403エラーになり、adminユーザーでログインすると全てのリソースにアクセスできます。
* それぞれのユーザーのアクセス範囲
** ログインしてない人のアクセス出来る範囲
/CONTEXT_ROOT
┣ public
┃┗ index.html
┗ index.html
- ログインしてない人は、usersとadminディレクトリにはアクセス出来ません。
- ルートのindex.htmlとpublicディレクトリの公開コンテンツのみにアクセス可能です。
** 会員のアクセス出来る範囲
/CONTEXT_ROOT
┣ public
┃┗ index.html
┣ users
┃┗ index.html
┗ index.html
- ログインした会員は、adminディレクトリにはアクセス出来ません。
- 公開コンテンツに加え会員用のusersディレクトリにアクセスが可能です。
** 管理者のアクセス出来る範囲
/CONTEXT_ROOT
┣ public
┃┗ index.html
┣ users
┃┗ index.html
┣ admin
┃┗ index.html
┗ index.html
- ログインした管理者は、全てのリソースにアクセス出来ます。
* ファイルの配置
/CONTEXT_ROOT
┣ WEB-INF
┃┗ web.xml
┣ public
┃┗ index.html
┣ users
┃┗ index.html
┣ admin
┃┗ index.html
┗ index.html
- これらの他に、Tomcat自身の設定ファイルserver.xmlとtomcat-users.xmlも設定が必要です。
* 認証情報をサーブレットやJSPで取得する方法
- ユーザー名 - HttpServletRequest#getRemoteUser
- ロール - HttpServletRequest#isUserInRole("user")
-- ロールは直接ロールを取得する方法はなく、isUserInRoleでユーザーがそのロールを持っているかを確認します。
- サーブレットの場合
#highlight(){{
// ユーザー名
String user = req.getRemoteUser();
// ロール
boolean isAdmin = req.isUserInRole("admin");}}
- JSPの場合
#highlight(){{
// ユーザー名
String user = request.getRemoteUser();
// ロール
boolean isAdmin = request.isUserInRole("admin");}}
- Tomcat7で動作確認していた感じでは、認証の必要なURLでないとユーザー名とロールは取得出来ないようです。
- 認証の必要ないURLで認証情報を取り扱うには、セッション等に保存して置いたほうがいいかもしれません。
* アンケート(このページの情報はお役に立ちましたか?)
#tvote("役に立った[4]","役に立たない[0]","分かりにくい[13]","間違っている[0]")
* 他のTomcatサンプルはこちら
#inc(Java/Tomcat/サンプル)
* コメント(バグ、間違い、こんな情報が欲しい等ありましたら)
#pcomment(reply)
2019-11-01T13:46:39+09:00
1572583599
-
Java/substring使用時のエラーと回避方法
https://w.atwiki.jp/chapati4it/pages/586.html
文字列切り取り関数である「substring」使用時のエラーの原因と回避方法のまとめです。
* 目次
#contents(,fromhere=true)
* java.lang.NullPointerException
NullPointerExceptionいわゆるヌルポが発生する場合、substringを仕掛けるオブジェクトが「null」(設定されていない)になっています。
** 例1:関数の戻り値が「null」
#highlight() {{
String s = getValue();
s = s.substring(1, 2);
}}
「getValue」関数の戻り値が「null」の場合「NullPointerException」が発生します。
*** 対策1-1:substringの直前にチェックを入れる
#highlight() {{
String s = getValue();
if (s != null) {
s = s.substring(1, 2);
}
}}
「getValue」の戻り値がnullでない場合だけsubstringを行うようチェックを追加しました。
実際には「戻り値がnullだった場合にはどうすべきか」というのも考えなければいけません。
*** 対策1-2:「getValue」関数の戻り値がnullにならないようにする
#highlight() {{
String getValue() {
String ret = null;
// ・・・関数の処理・・・
if (ret == null) {
return "retがnullの場合の値";
} else {
return ret;
}
}
}}
「getValue」が戻り値を返すところにチェックを挿入し、戻り値がnullの場合規定の値を返却するよう修正しました。
「直前の関数がnullを返さない」と分かっていればsubstringの直前にnullチェックする必要はありません。
*** 対策1-3:エラー処理を行う
#highlight() {{
try {
String s = getValue();
s = s.substring(1, 2);
} catch(Exception e) {
// ・・・エラー処理・・・
}
}}
「getValue」の戻り値がnullだったらエラーになってOK、エラー処理をしてしまえ!という対策です。
この場合「nullチェックしてnullだったらエラーを投げる」の方がよいのかもしれません。
** 例2:if文の通り具合で「null」になる場合
#highlight() {{
String s = null;
if (getHanteiKekka()) {
// ・・・判定結果がtrueの場合の処理・・・
s = "hogehoge";
} else {
// ・・・判定結果がfalseの場合の処理・・・
}
s = s.substring(1, 2);
}}
「getHanteiKekka」の戻り値がfalseの場合、「s」に値が設定されず「NullPointerException」が発生します。
*** 対策2-1:すべてのif文のルートでもれなく値を設定する
#highlight() {{
String s = null;
if (getHanteiKekka()) {
// ・・・判定結果がtrueの場合の処理・・・
s = "hogehoge";
} else {
// ・・・判定結果がfalseの場合の処理・・・
s = "mogemoge";
}
s = s.substring(1, 2);
}}
「判定結果がfalseの場合の処理」にも値を設定するように修正したので「NullPointerException」が発生しません。
今回の例ではif文のルートが2通りでしたが、if文が大量にあってルートを網羅しきれない場合はsubstringの直前でチェックするしかないでしょう。
*** 対策2-2:substringの直前にチェックを入れる
対策1-1と同じなのでコードは省略します。
*** 対策2-3:エラー処理を行う
対策1-3と同じなのでコードは省略します。
* java.lang.StringIndexOutOfBoundsException: String index out of range: xxx
オブジェクトの文字数が足りない場合のエラーです。
対策は「NullPointerException」の対策に+αの形になります。
** 例1:関数の戻り値が短い
#highlight() {{
String s = getValue();
s = s.substring(1, 2);
}}
この例では「getValue」関数の戻り値が0~1文字の場合「StringIndexOutOfBoundsException」が発生します。
2文字以上であれば例外は発生しません。
*** 対策1-1:文字数チェックをする
#highlight() {{
String s = getValue();
if (s != null && s.length() >= 2) {
s = s.substring(1, 2);
}
}}
「sがnull以外かつ2文字以上の場合」にsubstringを行うように修正しました。
nullチェックを入れているのは、sがnullだと「length」の方でエラーになる可能性があるためです。
*** 対策1-2:「getValue」関数の戻り値が2文字以下にならないようにする
#highlight() {{
String getValue() {
String ret = null;
// ・・・関数の処理・・・
if (ret == null || ret.length() <= 1) {
return "retがnullまたは1文字以下の場合の値";
} else {
return ret;
}
}
}}
こちらも「NullPointerException」の例に+αした内容ですが「戻り値がnullまたは1文字以下の場合」に規定の値を返すように修正してあります。
*** 対策1-3:エラー処理を行う
#highlight() {{
try {
String s = getValue();
s = s.substring(1, 2);
} catch(Exception e) {
// ・・・エラー処理・・・
}
}}
「getValue」の戻り値が1文字だったらエラーになってOK、エラー処理をしてしまえ!という対策です。
「NullPointerException」の例と同じです。
** 例2:if文の通り具合で文字数が不足する場合
#highlight() {{
String s = null;
if (getHanteiKekka()) {
// ・・・判定結果がtrueの場合の処理・・・
s = "hogehoge";
} else {
// ・・・判定結果がfalseの場合の処理・・・
s = "m";
}
s = s.substring(1, 2);
}}
「getHanteiKekka」の戻り値がfalseの場合、「s」が1文字のため例外が発生します。
*** 対策2-1:すべてのif文のルートで文字数が不足するしないように設定する
#highlight() {{
String s = null;
if (getHanteiKekka()) {
// ・・・判定結果がtrueの場合の処理・・・
s = "hogehoge";
} else {
// ・・・判定結果がfalseの場合の処理・・・
s = "mogemoge";
}
s = s.substring(1, 2);
}}
「判定結果がfalseの場合の処理」にも値を設定するように修正したので例外が発生しません。
今回の例ではif文のルートが2通りでしたが、if文が大量にあってルートを網羅しきれない場合はsubstringの直前でチェックするしかないでしょう。
*** 対策2-2:substringの直前にチェックを入れる
対策1-1と同じなのでコードは省略します。
*** 対策2-3:エラー処理を行う
対策1-3と同じなのでコードは省略します。
** 例3:第2パラメータより第1パラメータの方が小さい
#highlight() {{
String s = getValue();
s = s.substring(2, 1);
}}
これは「3文字目から1文字切り取り」という意図で記述しやすいコードです。
*** 対策2-1:パラメータを適正な値に変更する
#highlight() {{
String s = getValue();
s = s.substring(2, 3);
}}
「3文字目から1文字切り取り」の場合、パラメータは「2」と「3」が正解です。
これは気合で覚えるしかないです。
** 例4:第一パラメータが0未満の場合
#highlight() {{
String s = getValue();
int x = getKaishi();
int n = getMojisuu();
s = s.substring(x, x + n);
}}
「xからn文字切り取り」という意図の使い方ですが「x」が0未満の場合にも例外が発生します。
パラメータを何らかの処理で決定している場合に発生しやすい例外です。
*** 対策4-1:substringの直前にチェックを行う
#highlight() {{
String s = getValue();
int x = getKaishi();
int n = getMojisuu();
if (x >= 0) {
s = s.substring(x, x + n);
}
}}
「x」が0以上の場合にだけsubstringを行うように修正しました。
第2パラメータが「x + n」ではなく「y」などの場合は第2パラメータも含めてチェックを行う必要があります。
*** 対策4-2:0未満の値が設定されないようにする
#highlight() {{
int getKaishi() {
int ret = 0;
// ・・・getKaishiの処理・・・
if (ret < 0) {
return 0;
} else {
return ret;
}
}
}}
「getKaishi」関数を修正し、戻り値に0未満の値が設定されないようにする対策です。
*** 対策4-3:エラー処理を行う
対策1-3と同じなのでコードは省略します。
2019-09-16T16:49:25+09:00
1568620165