20211129のJavaに関する記事は11件です。

SpringSecurity 導入から基本的な認証フロー

はじめに Javaの学習を始めて最も躓いたSpringSecurityについて調べ実装することができたので、記録として残しておきます。完全に理解することができていない為、不備等あるかもしれませんがご了承ください。 SpringSecurityシリーズ 項目表 NO タイトル その1 SpringSecurity導入から基本的な認証フロー その2 SpringSecurityログインページをカスタマイズする その3 DBアクセス処理実装 実装 依存関係の追加 SpringSecurityを使うには、spring-boot-starter-securityを追加します。 ※今回はmavenでの実装とします。 pom.xml <!-- 中略 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- 中略 --> SpringSecurity設定 WebSecurityConfigurerAdapterを継承したクラスを用意します。 その1ではインメモリでユーザ認証を実現します。 DemoWebSecurity.java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public BCryptPasswordEncoder passwordEncoder() { // パスワードの暗号化用に、BCrypt(ビー・クリプト)を使用 return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { // アクセス権限の設定 http.authorizeRequests() // 制限なし .antMatchers("/").permitAll() // '/admin'は、'ADMIN'ロールのみアクセス可 .antMatchers("/admin").hasRole("ADMIN") // 他は制限あり .anyRequest().authenticated(); // ログイン処理の設定 http.formLogin(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // インメモリでユーザ認証処理 auth.inMemoryAuthentication() // ユーザ名'user',パスワード'user',ロール'USER'のユーザを追加 .withUser("user").password(passwordEncoder().encode("user")).roles("USER") .and() // ユーザ名'admin',パスワード'admin',ロール'ADMIN'のユーザを追加 .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN"); } } 画面遷移用ページの用意 ページ遷移の確認用に、必要最小限のControllerとViewファイルを用意しております。 Controller SecurityController @Controller public class SecurityController { @GetMapping public String top() { // top.htmlを表示 return "top"; } @GetMapping("/admin") public String admin() { // admin.htmlを表示 return "admin"; } @GetMapping("/sample") public String sample() { // sample.htmlを表示 return "sample"; } } View admin.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>adminページ</title> </head> <body> <h1>adminページ</h1> </body> </html> sample.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>sampleページ</title> </head> <body> <h1>sampleページ</h1> </body> </html> top.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>topページ</title> </head> <body> <h1>topページ</h1> </body> </html> 動作確認 topページ topページは認証外としているため、未ログイン状態でも閲覧することができます。 sampleページ sampleページはログイン状態でないと閲覧することができない。 /sampleでsampleページを表示する。 未ログイン状態である為、ログインページに遷移する。(SpringSecurityのデフォルトログインページ) フォームにユーザ名とパスワードを入力する。(今回はインメモリに設定) すると、sampleページに遷移することができる。 adminページ adminページはADMIN権限が付与されたユーザのみ閲覧することができる。 /adminでadminページを表示する。 ADMIN権限がないユーザが閲覧するとエラーになる。 ADMIN権限を付与されたユーザでログインする。 おまけ SpringSecurityにデフォルトである機能 ユーザ名、パスワード入力誤り ユーザ名、パスワードを誤るとログインページに戻ってきてエラー表示されます。 ログアウト /logoutでログアウトページに遷移します。(SpringSecurityのデフォルトログアウトページ) ボタンをクリックするとログアウトを実行して、ログインページに戻ります。 おわりに これでSpringSecurityの導入から基本的な認証フローを実装することができました。 間違っている箇所ありましたら、ご指摘いただければ幸いです。 次はログインページをカスタマイズしていきます。 その2 SpringSecurityログインページをカスタマイズする 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Security 導入から基本的な認証フロー

はじめに Javaの学習を始めて最も躓いたSpringSecurityについて調べ実装することができたので、記録として残しておきます。完全に理解することができていない為、不備等あるかもしれませんがご了承ください。 SpringSecurityシリーズ 項目表 NO タイトル その1 SpringSecurity導入から基本的な認証フロー その2 SpringSecurityログインページをカスタマイズ その3 DBアクセス処理実装 実装 依存関係の追加 Spring Securityを使うには、spring-boot-starter-securityを追加 ※今回はmavenでの実装とします pom.xml <!-- 中略 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- 中略 --> Spring Security設定 Spring Securityを有効にするためのConfigクラスを作成 WebSecurityConfigurerAdapterを継承したクラスを用意 その1ではインメモリでユーザ認証を実装する DemoWebSecurity.java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public BCryptPasswordEncoder passwordEncoder() { // パスワードの暗号化用に、BCrypt(ビー・クリプト)を使用 return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { // アクセス権限の設定 http.authorizeRequests() // 制限なし .antMatchers("/").permitAll() // '/admin'は、'ADMIN'ロールのみアクセス可 .antMatchers("/admin").hasRole("ADMIN") // 他は制限あり .anyRequest().authenticated(); // ログイン処理の設定 http.formLogin(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // インメモリでユーザ認証処理 auth.inMemoryAuthentication() // ユーザ名'user',パスワード'user',ロール'USER'のユーザを追加 .withUser("user").password(passwordEncoder().encode("user")).roles("USER") .and() // ユーザ名'admin',パスワード'admin',ロール'ADMIN'のユーザを追加 .withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN"); } } 画面遷移用ページの用意 ページ遷移の確認用に、必要最小限のControllerとViewファイルを用意しております。 Controller SecurityController @Controller public class SecurityController { @GetMapping public String top() { // top.htmlを表示 return "top"; } @GetMapping("/admin") public String admin() { // admin.htmlを表示 return "admin"; } @GetMapping("/sample") public String sample() { // sample.htmlを表示 return "sample"; } } View admin.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>adminページ</title> </head> <body> <h1>adminページ</h1> </body> </html> sample.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>sampleページ</title> </head> <body> <h1>sampleページ</h1> </body> </html> top.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>topページ</title> </head> <body> <h1>topページ</h1> </body> </html> 動作確認 topページ topページは認証外としているため、未ログイン状態でも閲覧することができます。 sampleページ sampleページはログイン状態でないと閲覧することができない。 /sampleでsampleページを表示する。 未ログイン状態である為、ログインページに遷移する。(Spring Securityのデフォルトログインページ) フォームにユーザ名とパスワードを入力する。(今回はインメモリに設定) すると、sampleページに遷移することができる。 adminページ adminページはADMIN権限が付与されたユーザのみ閲覧することができる。 /adminでadminページを表示する。 ADMIN権限がないユーザが閲覧するとエラーになる。 ADMIN権限を付与されたユーザでログインする。 おまけ Spring Securityにデフォルトである機能 ユーザ名、パスワード入力誤り ユーザ名、パスワードを誤るとログインページに戻ってきてエラー表示されます。  ログアウト /logoutでログアウトページに遷移します。(Spring Securityのデフォルトログアウトページ) ボタンを押すとログアウト実行してログインページに戻ります。 おわりに これでSpring Securityの導入から基本的な認証フローを実装することができました。 間違っている箇所ありましたら、ご指摘いただければ幸いです。 次はログインページをカスタマイズしていきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java tomcat

cd /usr/local curl -OL --header "Cookie: oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz" tar xvzf ./jdk-8u131-linux-x64.tar.gz mv jdk1.8.0_131 java export JAVA_HOME=/usr/local/java echo $JAVA_HOME /usr/local/java ``
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java tomcat setenv.sh

cd /usr/local curl -OL --header "Cookie: oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz" tar xvzf ./jdk-8u131-linux-x64.tar.gz mv jdk1.8.0_131 java export JAVA_HOME=/usr/local/java echo $JAVA_HOME /usr/local/java /usr/local/tomcat/bin/ #メモリ見ときましょう free vi setenv.sh -Xmx 最大ヒープサイズ(最大メモリ使用量) -Xms 初期ヒープサイズ(初期メモリ使用量) -Xss プロセスに割り当てられるスタックサイズ(228k以上必要になります) 参考にするとこんな感じかな ヒープの初期サイズ リージョンサイズ 4GB未満          1MB 4GB以上 ~ 8GB未満 2MB 8GB以上 ~ 16GB未満 4MB 16GB以上 ~ 32GB未満 8MB 32GB以上 ~ 64GB未満 16MB 64GB以上      32MB #①注意点 初期サイズXmsと最大サイズXmxが大きく異る場合は相談しましょう。 ```sh CATALINA_OPTS="-server -Xmx1024m -Xms1024m -Xss228k" export CATALINA_OPTS /usr/local/tomcat/bin/shutdown.sh Using CATALINA_BASE: /usr/local/tomcat Using CATALINA_HOME: /usr/local/tomcat Using CATALINA_TMPDIR: /usr/local/tomcat/temp Using JRE_HOME: /usr/local/java Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar Using CATALINA_OPTS: -server -Xmx1024m -Xms1024m -Xss228k /usr/local/tomcat/bin/startup.sh Using CATALINA_BASE: /usr/local/tomcat Using CATALINA_HOME: /usr/local/tomcat Using CATALINA_TMPDIR: /usr/local/tomcat/temp Using JRE_HOME: /usr/local/java Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar Using CATALINA_OPTS: -server -Xmx1024m -Xms1024m -Xss228k Tomcat started. ps aux | grep tomcat root 27344 9.2 7.2 4028616 136544 pts/0 Sl 22:13 0:07 /usr/local/java/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -server -Xmx1024m -Xms1024m -Xss512k -Dignore.endorsed.dirs= -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start root 27368 0.0 0.0 112812 980 pts/0 S+ 22:14 0:00 grep --color=auto tomcat
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Effective Java 第3版]項目18 - 継承よりもコンポジションを選ぶ

継承はコードを再利用するには便利な機能ですが、常に既存のメソッドを継承し、拡張することがベストな方法とは限りません。 サブクラスとスーパークラスが同じ開発者の管理下にあり、同じパッケージ内にある場合は比較的安全といえます。 しかしパッケージをまたがり具象クラスを継承することは危険です。 継承の不適切な使用例 HashSetが生成させてからいくつ要素が追加されたかを確認するため、getAddCountを実装します。 要素の挿入回数 addCountをフィールドに保持し、HashSetクラスの要素を追加できるaddとaddAllをオバーライドし要素が追加されるとaddCountをカウントアップします。 InstrumentHashSet.java public class InstrumentedHashSet<E> extends HashSet<E> { // 要素の挿入回数 private int addCount = 0; @Override public boolean add(E e) { addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } } この実装では、addAllが呼ばれると期待する結果通り動作しません。 要素を3つ追加すると、getAddCountで6が返ってきます。 App.java public class App { public static void main(String[] args) { InstrumentedHashSet<String> set = new InstrumentedHashSet<String>(); set.addAll(Arrays.asList("AAA", "BBB", "CCC")); System.out.println(set.size()); //→3 System.out.println(set.getAddCount()); //→6 } } addAllメソッドは内部でaddメソッドを使って実装されています。 InstrumentedHashSetのaddAllを呼び出すと、addCountに要素の数を足して、スーパークラスのaddAllを呼び出します。 HashSetのaddAllでは、個々の要素に対して、InstrumentedHashSetでOverrideされているaddを呼び出すため、2重にカウントアップされてしまいます。 実装の修正を検討 新たにメソッドを追加することで、この問題は解消されるますが、安全とは言えません。 スーパークラスが後にメソッドを追加して、同じシグニチャでことなる戻り値を定義すると、サブクラスのメソッドはコンパイルできなくなることもあります。 コンポジション 上述する問題を解消することができるのがコンポジション(composition)という考え方です。 既存クラスを拡張するのではなく、新たなクラスに既存のクラスのインスタンスをprivateフィールドで持たせ、既存クラスが新たなクラスの構成要素となります。 新たなクラスのメソッドは既存クラスのインスタンスに対して、メソッドを読み出しそのまま結果を返します。これを転送(fowarding)と呼びます。 コンポジションを利用すれば、新たなクラスは既存のクラスの実装の詳細に依存することがなくなります。 InstrumentedSet.java //ラッパークラス-継承の代わりにコンポジションを使用 public class InstrumentedSet<E> extends ForwardingSet<E> { private int addCount = 0; public InstrumentedSet(Set<E> s) { super(s); } @Override public boolean add(E e) { addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } } ForwardingSet.java //再利用可能な転送クラス public class ForwardingSet<E> implements Set<E> { //既存クラスをpravateフィールドで持つ private final Set<E> s; public ForwardingSet(Set<E> s) { this.s = s; } @Override public boolean add(E e) { return s.add(e); } @Override public boolean addAll(Collection<? extends E> c) { return s.addAll(c); } //他SetクラスのメソッドのOverrideは省略・・・ App.java public class App { public static void main(String[] args) { Set<String> hashSet = new HashSet<String>(); InstrumentedSet<String> set = new InstrumentedSet<String>(hashSet); set.addAll(Arrays.asList("A", "B", "C")); System.out.println(set.size()); //→3 System.out.println(set.getAddCount()); //→3 } } 継承とコンポジションの使い分け 継承 サブクラスがスーパークラスのサブタイプである場合に拡張するべきです。 サブクラスとスパークラスとの間に「is-a」の関係が存在しているか考え、満たす場合拡張するようにします。 「B is a A」は「BはAである」という意味となります。 「犬は動物である」、「車は乗り物である」のような関係を持っている場合、継承を使うとよいでしょう。 コンポジション 継承の「is-a」に対して「has-a」の関係がある場合コンポジションを使うとよいと考えられています。 「B has a A」は「BはAを含んでいる」という意味となります。 「タイヤは車に含まれている」、「メモリはPCに含まれている」のような関係を持っている場合、コンポジションを使うとよいでしょう。 また以下のような場合にもコンポジションが推奨されているようでした。 明確に「is-a」の関係が成立すると言えない is-aの関係は成立するが、パッケージをまたがる継承となってしまう、またはスーパークラスの実装を明確に理解できない まとめ Javaの便利な機能の継承ですが、継承するべきではないパターンがあり、不適切に継承することで意図しない動作を起こす可能性があります。 継承を利用する場合は「is-a」の関係が成立するか改めて考え実装するようにしましょう。 もし「is-a」が成立しなければ、コンポジション、転送を使うようにしましょう。 参考 https://thekingsmuseum.info/entry/2015/09/16/003849 https://techlib.circlearound.co.jp/entries/extends-vs-composition/ https://4geek.net/difference-between-inheritance-and-composition/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

break、continue、label、returnの使い方メモ

目次 1.break 2.continue 3.label 4.return 5.さいごに 1. break 直前のループを抜ける。 List<Integer> numberList = new ArrayList<Integer>(); numberList.add(1); numberList.add(2); numberList.add(3); // 拡張for文でnumberListをぐるぐる回す for (Integer number : numberList) { System.out.println(number); // numberが2のとき直前のループを抜ける if (number == 2) { break; } } 出力結果は下記の様になる。 1 2 ループが二重になっている場合はこちら。 List<String> countList = new ArrayList<String>(); countList.add("1周目"); countList.add("2周目"); countList.add("3周目"); List<Integer> numberList = new ArrayList<Integer>(); numberList.add(1); numberList.add(2); numberList.add(3); for (String count : countList) { System.out.println(count); for (Integer number : numberList) { System.out.println(number); // numberが2のとき直前のfor文を抜ける if (number == 2) { break; } } System.out.println("おわり"); } 出力結果は下記の様になる。 1周目 1 2 おわり 2周目 1 2 おわり 3周目 1 2 おわり 2. continue continue文以降の処理をスキップし、 次の要素のループ処理へ移る。 List<Integer> numberList = new ArrayList<Integer>(); numberList.add(1); numberList.add(2); numberList.add(3); for (Integer number : numberList) { if (number == 2) { continue; } System.out.println(number); } 上記例ではnumberが2のときcontinue以降の出力処理をおこなわず、 numberListの次の要素のループに移る。 出力結果は下記の様になる。 1 3 ループが二重になっている場合はこちら。 List<String> countList = new ArrayList<String>(); countList.add("1周目おわり"); countList.add("2周目おわり"); countList.add("3周目おわり"); List<Integer> numberList = new ArrayList<Integer>(); numberList.add(1); numberList.add(2); numberList.add(3); for (String count : countList) { for (Integer number : numberList) { if (number == 2) { continue; } System.out.println(number); } System.out.println(count); } 上記例ではnumberが2のときnumber出力処理を行わず、 numberListの次の要素のループ処理に移る。 出力結果は下記の様になる。 1 3 1周目おわり 1 3 2周目おわり 1 3 3周目おわり ページ上部へ戻る 3. label ループが二重以上になっている場合にlabelを付けることによって、 breakやcontinueで抜けるループを指定することができる。 ① breakの場合 List<String> countList = new ArrayList<String>(); countList.add("1周目"); countList.add("2周目"); countList.add("3周目"); List<Integer> numberList = new ArrayList<Integer>(); numberList.add(1); numberList.add(2); numberList.add(3); // ラベル名をつける firstLabel:for (String count : countList) { System.out.println(count); for (Integer number : numberList) { System.out.println(number); if (number == 2) { // ラベルを指定 break firstLabel; } } System.out.println("おわり"); } breakで抜けることができるのは直前のfor文だが、 labelを使うことによって抜けるfor文を指定することができる。 出力結果は下記の様になる。 1周目 1 2 ② continueの場合 List<String> countList = new ArrayList<String>(); countList.add("1周目"); countList.add("2周目"); countList.add("3周目"); List<Integer> numberList = new ArrayList<Integer>(); numberList.add(1); numberList.add(2); numberList.add(3); // ラベル名をつける firstLabel:for (String count : countList) { for (Integer number : numberList) { if (number == 2) { // ラベルを指定 continue firstLabel; } System.out.println(number); } System.out.println(count); } labelを使うことによって、指定したlabelが付いたのfor文の、 次の要素のループを行うことができる。 出力結果は下記の様になる。 1 1 1 ページ上部へ戻る 4. return メソッドを抜ける。(呼び出し元に処理を戻す) public static void main(String args[]) { List<String> dayList = new ArrayList<String>(); dayList.add("月曜日"); dayList.add("水曜日"); dayList.add("日曜日"); for (String day : dayList) { System.out.println(day); // 平日かどうか出力するメソッドの呼び出し outputIsWeekDay(day); } // 平日かどうか出力するメソッドの呼び出し private static void outputIsWeekDay(String day) { if (day.equals("土曜日") || day.equals("日曜日")) { System.out.println("これは平日ではありません"); return; } System.out.println("これは平日です"); } checkWeekDayメソッドif文内にreturn文を記載することによって、 「これは平日ではありません」が出力されたあと「これは平日です」が出力されないようになっている。 また、メソッドの最後の } に到達すると処理は呼び出し元に戻るので、 戻り値がないときはメソッド最後のreturn文記載は不要。 (そのため「これは平日です」の出力処理後にreturnを記載していない) 出力結果は下記の様になる。 月曜日 これは平日です 水曜日 これは平日です 日曜日 これは平日ではありません ページ上部へ戻る 5. さいごに ここまで読んでいただきありがとうございます! 今回は現場で実装を行っていた際に、間違えやすいなと思ったものを個人的にまとめてみました。 自分のアウトプットの内容が誰かのお役に立てると嬉しいです。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのシステムでcsvからインポートする機能を実装する方法

まずはJSPから。 formは以下のように書く。 <form id="" action="" method="POST" enctype="multipart/form-data"> inputのタイプはfileに <div class="tr"> <label for="csv" class="th">csv:</label> <div class="td"> <input type="file" id="csv" name="csv" required> </div> </div> JSPは以上です。 サーブレットはアノテーションのすぐ下に以下を追記 @MultipartConfig( maxFileSize=10000000, maxRequestSize=10000000, fileSizeThreshold=10000000 ) doPostを以下のように記述 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 文字化け対策 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); // 接続情報 db = DB接続情報を代入; Connection conn = null; // SQL PreparedStatement pstmt1 = null; // 送信情報の取得 Part csv = request.getPart("csv"); BufferedReader br = null; try { // データベース接続情報取得 conn = db.getConnection(); // csv読み込み InputStream is = csv.getInputStream(); InputStreamReader isr = new InputStreamReader(is); br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { String[] data = line.split(","); // SQL実行 String sql1 = "INSERT INTO table(aaa,bbb,ccc) VALUES(?,?,?)"; pstmt1 = conn.prepareStatement(sql1); pstmt1.setString(1, data[0].trim()); pstmt1.setString(2, data[1].trim()); pstmt1.setString(3, data[2].trim()); pstmt1.executeUpdate(); } } catch (Exception e) { System.out.println(e.getMessage()); } finally { try { pstmt1.close(); } catch (SQLException e) { } try { br.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } response.sendRedirect("/"); } csvファイル情報取得部分 Part csv = request.getPart("csv"); BufferedReader br = null; csv読み込み部分 InputStream is = csv.getInputStream(); InputStreamReader isr = new InputStreamReader(is); br = new BufferedReader(isr); String line; while文でデータベースに保存 while ((line = br.readLine()) != null) { String[] data = line.split(","); // SQL実行 String sql1 = "INSERT INTO table(aaa,bbb,ccc) VALUES(?,?,?)"; pstmt1 = conn.prepareStatement(sql1); pstmt1.setString(1, data[0].trim()); pstmt1.setString(2, data[1].trim()); pstmt1.setString(3, data[2].trim()); pstmt1.executeUpdate(); } catchで例外処理 catch (Exception e) { System.out.println(e.getMessage()); } 最後にbrを解放して終わり try { br.close(); } catch (Exception e) { System.out.println(e.getMessage()); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのシステムで画像を取り扱う方法

まずはJSPのformで下記を追記します。 enctype="multipart/form-data" こんな風になります。 <form action="" method="POST" enctype="multipart/form-data"> インプットタグはタイプをfileにします。 <div class="tr"> <label for="logo">画像:</label> <div class="td"> <input type="file" id="logo" name="logo"> </div> </div> JSPは以上です。 サーブレットでは以下の記述をアノテーションのすぐ下に追記します。 @MultipartConfig( maxFileSize=10000000, maxRequestSize=10000000, fileSizeThreshold=10000000 ) 画像データの取り込み部分 // 画像のファイル名取得 Part part = request.getPart("logo"); String logo = Paths.get(part.getSubmittedFileName()).getFileName().toString(); String logo_name = logo.isEmpty() ? "" : logo; logo_nameは文字列としてDBに保存します。画像ファイルそのものはまずWEB-INFと同じディレクトリに空のフォルダを作ります。(ここではlogoという名前でフォルダを作ります。) 次に以下のコードで記述します。 // 画像アップロード String path = getServletContext().getRealPath("/logo"); part.write(path + File.separator + logo_name); 以上で画像データの保存はできました。 保存した画像データの表示は以下の記述でできます。 <img src="/コンテキストルート/logo/DBに保存したlogo_nameの文字列">
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ajaxのソースコード

実務でJavaのシステムで実装したAjaxのソースコードを自分用にメモとしてまとめました。 まずはJavaScriptでイベントを作成し、通信する。 $('#button').click(function() { var req = new XMLHttpRequest(); var url = 'コンテキスト以降のURL'; req.open('GET',url); req.send(); req.onreadystatechange = function() { if (req.readyState === 4 && req.status === 200) { let info = (req.responseText)?JSON.parse(req.responseText):null; if (info) { console.log(info); } } } }); 指定したURLのサーブレットを作ってJSONデータを返す。 // レスポンス用JSON文字列生成 String resData = "{\"mojiretsu1\":\"" + "mojiretsu1" + "\",\"mojiretsu2\":\"" + "mojiretsu2" + "\",\"mojiretsu3\":\"" + "mojiretsu3" + "\"}"; // レスポンス処理 response.setContentType("text/plain"); response.setCharacterEncoding("utf8"); PrintWriter out = response.getWriter(); out.println(resData); 文字列はtry,catch構文でデータベースに接続してデータベースから取ってきたり、サーブレットで生成したりする。 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

個人的「Java Bronze試験つまずいた項目」5選

先日、オラクル認定資格のJava Bronze試験を受験しました。Javaの資格試験としてはもっとも難易度の低いものとして知られていますが、プログラミング初心者にとってはかなり難しいタイプの試験なのではないかと感じました。 今回の記事ではJava Bronze試験の学習経験を踏まえ、つまづきやすかったり、なかなか覚えられなかった文法項目を5つ取り上げてまとめました。 このJava Bronze試験にはバージョンがさまざまあるようなので、ご注意ください。 受験した試験:Java SE Bronze (試験コード1Z0-818) 1.使用した主な参考書や教材 Java Bronze試験の対策本としてはいくつか有名なものがあります。私は「黒本」と言われる「徹底攻略Java SE Bronze問題集[1Z0-818]対応」を5周ほどし、対策しました。参考書としては結局黒本のみを使用しました。 そのほか「紫本」という「オラクル認定資格教科書 Javaプログラマ Bronze SE(試験番号1Z0-818)」がありますが、比較的難易度が低いという評判を聞きます。まず紫本で基礎を押さえてから黒本に移るのも手かもしれません。 またJava入門書として「スッキリわかるJava入門 第3版 (スッキリわかる入門シリーズ) 」が有名です。初学者にもわかりやすいですが、分量が多く、Java Bronze試験を念頭に置いた書籍ではないため、試験対策としては使いづらいのではないかと思います。試験問題を解きながら理解が及ばなかった項目について、理解の助けとして利用する分には便利かもしれません。私も少しだけ読みました。 また、YouTubeを利用しての学習も行いました。項目ごとにわかりやすく解説した動画も豊富に上がっているため理解の助けになります。以下リンクのJava Bronze試験要点まとめ公式動画も2時間分ありますので、試験直前に理解度確認のために利用しました。 Oracle Certified Java Programmer, Bronze SE 7 / 8 認定資格試験 ポイント解説セミナー(1) Oracle Certified Java Programmer, Bronze SE 7 / 8 認定資格試験 ポイント解説セミナー(2) 次節から早速、「Java Bronze試験つまずいた項目」5選の紹介をしていきます。 2.Java Bronze試験つまずいた項目」5選 ①シグネチャの同じメソッドを持つインスタンスを別の型で扱う スーパークラスとサブクラスが同じシグネチャのメソッドを持っている以下のような場合を考えます。 Main.java public class A { public void speak() { System.out.println("Hello."); } public class B extends A { public void speak() { System.out.println("Good morning."); } } public class Main { public static void main(String[] args) { A a = new B(); a.speak(); } } この場合、Mainメソッドの出力結果として何が出てくるかが問題として問われます。BのインスタンスをA型で扱っているため、「Hello.」と「Good morning.」どちらが出力されるかが観点になってきます。 このパターンの問題は、どのクラスがnewされているかで考えればよいです。今回はBクラスがインスタンス化されているため、どんな型で扱われていようとspeakメソッドがB型のものでオーバーライドされることになります。すなわち、出力結果は"Good morning."となります。 サブクラスのインスタンスをスーパークラスの型で扱うということは、サブクラスの持つスーパークラスの要素部分のみ抜き出しインスタンスとして扱うということです。つまりサブクラス固有のメソッドなどが無視されます。今回は両クラスがシグネチャの同じメソッドを持っているため、Aクラスのspeakメソッドの内容がBクラスのメソッドの内容に上書きされます。 ②例外が出てくるパターン Java Bronzeでは、出題されるコードがなんかおかしいなと感じられた場合の正答は、多くの場合「コンパイルエラー」になります。しかし例外が発生するわずかなパターンが出題されることがありますので、ここだけ押さえておけば確実に得点につながります。 (参考サイト:例外とは) そもそも例外とは、コンパイルしてjavaの文法的には正しかったものの、実際に動かしてみるとうまく行かなかった場合に発生するものです。一方のコンパイルエラーはそもそも文法が間違っているときに、コンパイル時に発生するものです。コンパイルエラーの例としては、カッコが足りないなどの単純な記述ミスや、他クラスのprivateフィールドに直接アクセスするなどのミスが該当します。ちなみに、カッコが足りないなどのレベルの、間違い探しのようなひっかけ問題は、本試験では基本的に出題されないようです。 それでは例外になるパターンとしてはどのようなものがあるのでしょうか?Javaの初歩的な例外パターンを洗い出したところ、以下の3つが挙げられました。 Ⅰ.配列で、要素数を超えるアクセスをした場合(初期化していない配列も含む) これはごく単純なパターンです。例えば要素数が3個しかない配列の4番目の要素にアクセスしようとしたときに発生します。 ちなみに以下のような場合も同じ理由で例外が発生します。 Main.java //「java Main」というコマンドで以下のプログラムを実行 public class Main { public static void main(String[] args) { System.out.println(args[0]); } } 普段はあまり意識されませんが、mainクラスに「String[] args」が指定されていることからわかるように、mainクラスは文字列の配列を引数に受け取ることができます。プログラム実行時に「java Main 文字列, 文字列, ...」と指定すれば「args」という配列に文字列の値が入ってきます。 「java Main」というコマンドでプログラムを実行すると、「args」というインスタンスは生成されるものの、値が何も入っていない状態になります。この状態で0番目の要素にアクセスしようとすると例外が発生するわけです。 Ⅱ.明示的なダウンキャスト まずはダウンキャストについて、コンパイルエラーが発生するパターンを考えてみます。 A.java public interface A { //Aというインターフェース } B.java public class B implements A { //インターフェースAを実装したBクラス } C.java public class C extends B { //Bクラスを継承したCクラス } Main.java public class Main { public static void main(String[] args) { B b = new B(); //Bのインスタンスを生成する(AとBの差分を持っている) A a = b; //Aの差分を持った変数aを宣言する(Bの差分がなくなり、Aの差分しか持っていない) C c = a; //変数aをそのままC型に当て込もうとする。変数aはBやCの差分を持っていないためコンパイルエラーとなる } } この例ではAというインターフェース、Aを実装したBクラス、Bクラスを継承したCクラス、Mainクラスが宣言されています。「 B b = new B();」でBクラスをインスタンス化することで、BクラスはBクラス自体の差分はもちろんのこと、実装元のインターフェースAの差分を持ちます。 「 A a = b;」で、先ほどインスタンス化したBクラスをA型で扱おうとしています。つまりBクラスのA型の部分だけ抜き出して変数aに格納しています。これによって元々あったBクラスの差分はなくなってしまいます。このように生成したインスタンスを継承元、実装元の上流の型に当て込むことをアップキャストと呼びます。 アップキャストの逆で、継承先、実装先の型でインスタンスを扱おうとすることをダウンキャストと呼びます。アップキャストするときは必ずインスタンスが継承元、実装元の差分を持っているため、自動的に問題なく行われます。一方でダウンキャストについてはインスタンスが継承先、実装先の差分を持っているとは限らないため、型に整合性があることを明示的に示す必要があります。 例の「 C c = a;」では、Aの差分のみを持っている変数aの値をC型で扱おうとしています。C型は、インターフェースAを実装しているBクラスを継承しているため、A、B、C全ての型の差分を持っていることになります。変数aの値をC型で扱ってしまうと、仮にB、C型の差分内容を使おうとなったときに不釣合いが生じてしまいます。このような現象を防ぐために、ダウンキャストする際は一律で明示的に型の整合性を示す必要があり、明示的に示していない今回の例はコンパイルエラーとなります。 それでは、mainクラスを以下のように書くとどうなるでしょうか。 Main.java public class Main { public static void main(String[] args) { B b = new B(); //Bのインスタンスを生成する(AとBの差分を持っている) A a = b; //Aの差分を持った変数aを宣言する(Bの差分がなくなり、Aの差分しか持っていない) C c = (C)a; //変数aをC型に変換してC型に当て込もうとする。 } } 「C c = (C)a;」というように、変数aはC型で扱えるよと明示的に示しているため、文法的には問題ないと判断されます。しかし実際は変数aはAの差分しか持たないため、実行時に型の生合成がつかなくなってしまいます。こういった場合は実行時に例外が発生します。 ダウンキャストをする場合は、現在の型に整合性があるかどうかのみ考慮されます。そのため仮に、以下のように元々の型に整合性があるダウンキャストを行ったとしても例外が発生します。 Main.java public class Main { public static void main(String[] args) { B b = new B(); //Bのインスタンスを生成する(AとBの差分を持っている) A a = b; //Aの差分を持った変数aを宣言する(Bの差分がなくなり、Aの差分しか持っていない) B nextB = (B)a; //変数aをB型に変換してB型に当て込もうとする。変数aはすでにB型の差分を失っているため整合性が取れず、例外となる } } Ⅲ.予期せぬ型で値が入力される このパターンについては問題集、本試験で出会ったことはありませんが、要求されている型とは違う型の引数が指定された場合などに例外が起こります。 (参考サイト:IllegalArgumentException IllegalStateExceptionの使い方) ③コンストラクタに関わるコンパイルエラーパターン 他のクラスを継承した場合のデフォルトコンストラクタ追加などについても紛らわしさがあるため、ここで整理してみます。 前提として、自クラスの別のコンストラクタを呼び出したいときには「this()」、継承元のスーパークラスのコンストラクタを呼び出したいときは「super()」キーワードを用います。 それでは以下で、コンパイルエラーになるパターンをいくつかみていきましょう。 Ⅰ.コンストラクタ呼び出しが共存するパターン コンストラクタはインスタンスの準備をするものです。そのためインスタンス準備の前に処理が発生すると困ってしまいます。コンストラクタ呼び出しの前に処理を書くことはできないので「this()」と「super()」いずれも、コンストラクタの一番最初でしか使用することが出来ないことになります。 このルールがあるため、以下のようにコンストラクタ内で並列して2つのコンストラクタ呼び出しを行っているパターンはコンパイルエラーになります。 this(); super(); Ⅱ.引数ありのコンストラクタがあるのに、引数が指定されていないパターン 以下のように引数ありのコンストラクタが宣言されている場合、引数なしのデフォルトコンストラクタは自動追加されません。そのためインスタンス生成時に引数を渡さなかった場合はもちろんコンパイルエラーになります。 Sample.java Sample s = new Sample() //引数指定なしでインスタンス生成 ~省略~ class Sample{ public Sample(int a){ //処理 } //処理 } Ⅲ.コンストラクタ呼び出しの引数としてstaticでないフィールドを指定している コンストラクタはインスタンス生成時に最初に実行されるメソッドです。そのためstaticではないフィールドを指定すると、まだ準備がなされていないフィールドを参照することになります。staticフィールドはインスタンスを生成しなくても使えるので問題ありませんが、それ以外の場合はコンパイルエラーになってしまいます。 Sample.java public class Sample { public String argument = “example”; public String name; public Sample() { //引数なしのコンストラクタ this(argument); //staticでない変数を指定して別の自クラスのコンストラクタ呼び出し } public Sample(String name) { this.name = name; } } ④データ隠蔽と情報隠蔽の違い どちらも「隠蔽」という言葉が使われている、かつ「データ」と「情報」の意味合いも似ているため混同しがちな項目でした。 (参考サイト:【Java Bronze学習】カプセル化・データ隠蔽・情報隠蔽の違い) カプセル化とセットで使われるのがデータ隠蔽です(カプセルとデータどちらもカタカナ、というふうに覚えました)。 カプセル化というのは関連する変数やメソッドを同じクラスにカプセルのようにまとめてしまおうという考え方です。例えば以下のような二つのクラスを考えましょう。 public class employee { private String department; private String name; public void introduce(String department, String name) { System.out.println(department + “の” + name + “と申します。”); } } public class product { private int priceWithoutTax; private double taxRate; public int calculateConsideringTaxRate(int priceWithoutTax, double taxRate) { return priceWithoutTax + priceWithoutTax * taxRate; } } employeeクラスには従業員に関する変数と処理、productクラスには商品に関する変数と処理をまとめています。システムに改修が入った時、関係する要素が別々のクラスに散らばっていると調査に時間がかかってしまい、保守性が高いシステムとは言えません。関連する変数や処理をひとつにまとめて構造をわかりやすくするのがカプセル化です。 例えば従業員クラスの中で商品の価格を変えてしまうような処理があったとすると、無関係なクラスが勝手にクラスの内容に影響を及ぼすことになってしまいます。そのような事態を防ぐために変数にprivate修飾子をつけ、他クラスから勝手に参照できないようにします。これがデータ隠蔽という考え方です。カプセル化、データ隠蔽、プライベート、いずれもカタカナなので私はまとめて覚えました。 一方の情報隠蔽は抽象化の維持のために使われる考え方です。情報隠蔽、抽象化いずれも漢字表記なのでまとめて覚えました。 そもそもの抽象化とは、各クラスの共通部分に着目する考え方のことです。例えば、「殴る」という処理を持つ「人間」クラス、「噛む」という処理を持つ「ヘビ」クラス、「ひっかく」という処理を持つ「猫」クラスがあるとします。それぞれをこのまま扱おうとすると散らばった3つのクラスそれぞれについて考える必要が出てきてしまい、改修時などに時間がかかってしまいます。 これを一般化して「攻撃」処理を持つ「生き物」クラスというものをひとつ用意して、殴るや噛むなどの具体的な実装は「生き物」クラスを継承したそれぞれのクラスに委ねるというのが抽象化の考え方です。仮に「防御」処理を追加したくなった時、「生き物」クラスに「防御」処理を追加してそれぞれのクラスで具体的に実装することでまとめて扱うことができるようになります。 以下に引用した画像では「社員」という一般化したクラスを用意し、「働く」処理の具体的な内容の実装を各クラスに委ねています。ちなみにこの「社員」クラスに当たるものはインターフェースと呼ばれ、インターフェースでは抽象メソッドというものを定義し、継承先のクラスに具体的な実装を強制することができます。 ⑤Javaプログラムの実行方式 java bronze試験のほとんどはソースコードを見て想定される動きを考えるものが多いですが、単純な知識を問うものもいくつか出題されます。このような知識問題はいっそ捨ててかかる方も多いようですが、基本的なところは得点しやすいので押さえておくべきかなと感じました。 プログラム言語の主な二つの実行方法として、「事前コンパイル方式」と、「インタープリタ方式」があります。しかしjavaはこの二者の中間的な実行方法を採用しており、それを「実行時コンパイル方式」と呼びます。 (参考サイト:インタープリタ方式とコンパイル方式) インタープリタ方式では、インタープリタが実行時に人間向けのソースコードを読み込み、OS向けのネイティブコードに変換(コンパイル)します。こうすることでプログラムをどのようなOSでも実行できます。しかし実行速度が落ちてしまうというデメリットもあります。 事前コンパイル方式では人間向けのソースコードを事前に機械語の実行ファイルにコンパイルしておき、OSでそれを読み込んで実行する方式です。すでにコンパイルされたファイルを読み込むため実行速度が速いというメリットがあります。一方でOS依存の実行ファイルが作られてしまうというデメリットがあります。 javaではOSに依存しないかつ実行速度の速いプログラムを生成するために、実行時にコンパイルを行います。実行時にソースコードが中間コード(クラスファイル)にコンパイルされます。さらにその中間コードを、JVMという仮想的なコンピュータが読み込みます。このように事前にJVM用のコンパイルを行いつつ、OSごとにJVMを用意すればOS非依存にできるため、二つの実行方式のいいとこ取りができるというわけです。 (参考画像:JVM Architecture) 実行時コンパイル方式を含めた以上三種類の実行方式については、何度も実行の流れを確認して覚えていくしかなさそうです。 またjavaプログラムの実行に関連して、JVMやJREなど英語のアルファベット表記の用語がいくつか登場して混同しがちになりました。包含関係などをに簡単にまとめてみます。 名称 説明 JVM 実行時にクラスファイルを読み込む仮想的なコンピュータ JRE javaプログラムの実行に必要なJVMやライブラリ、コンポーネントをまとめたもの JDK JREに加えてコンパイラなどの開発ツールを含んでいる Hotspot VM 実行時コンパイル方式を可能にするJVMの一種(参考記事) 3.最後に Java Bronze試験に合格したからといってプログラミングがスイスイ進むというわけではありません。しかし知識の部分では証明になりますし、上位試験を受ける際の演習にもなるため、手軽で良い試験だと思います。受験料も高額なため、万全の対策をして一発合格をしたいですね。 参考サイト: ◯勉強法について Oracle認定資格のJava Bronzeレベルとは?勉強方法4つを解説 【2021/10 更新】Java Bronze SE を高確率で一発合格する方法 ◯サンプル問題の載っているサイト Java初心者の登竜門! Java Bronze試験で間違えやすい問題6選 Oracle Java Bronzeテスト対策!簡単なことなのに私がよく間違える問題 7問! Oracle認定Javaプログラマ(OCJ-P)試験の練習問題(複数クラス編) ◯つまずきやすいポイント解説 Java Bronzeで引っ掛かりがちな問題8選!難易度や試験範囲も解説 【Java資格】Bronze(OCJ-P)の出題問題について徹底解剖 ◯受験方法の説明 【Oracle認定Javaプログラマ】Bronze試験の申し込み方法と合格率を上げる勉強法 Java Bronze資格試験の申し込み手順がややこしすぎるぅぅぅぅ泣 【Java Bronze(ブロンズ)】試験の申し込みから対策法まとめ ◯その他本記事作成の参考としたもの 徹底攻略Java SE Bronze問題集[1Z0-818]対応 オラクル認定資格教科書 Javaプログラマ Bronze SE(試験番号1Z0-818) スッキリわかるJava入門 第3版 (スッキリわかる入門シリーズ) Oracle Certified Java Programmer, Bronze SE 7 / 8 認定資格試験 ポイント解説セミナー(1) Oracle Certified Java Programmer, Bronze SE 7 / 8 認定資格試験 ポイント解説セミナー(2) 例外とは IllegalArgumentException IllegalStateExceptionの使い方 【Java Bronze学習】カプセル化・データ隠蔽・情報隠蔽の違い 抽象クラス(Abstract Class) インタープリタ方式とコンパイル方式 JVM Architecture HotSpot VMについて
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Progate Java編 I 個人的備忘録

出力 Javaで出力するには、System.out.println()を使う。 Main.java System.out.println("Hello World"); コンソール Hello World Javaの構造 Javaの基本的な構造は、クラス部分、メソッド部分、処理部分に分けられる。 クラス部分の中にメソッド部分があり、そのメソッド部分の中に処理部分がある。 Main.java class Main { // クラス部分 public static void main(String[] args) { // メソッド部分 System.out.println("Hello World"); // 処理部分 } } 変数定義とデータ型 Javaでは変数を定義するときに「データ型」を指定する必要がある。 ・数字の変数定義の場合、int 変数名で定義する。 ・文字列の変数定義の場合、String 変数名で定義する。 Main.java int number; number = 10; System.out.println(number); // 変数定義と同時に値を代入することもできる(こっちが基本) String text = "Hello World"; System.out.println(text); コンソール 10 Hello World 変数の更新 変数を更新するときは、データ型をつけない。 Main.java int number = 3; number = 5; System.out.println(number); コンソール 5 少数を表すデータ型 整数の数字のデータ型を表すのがint型であるのに対し、少数の数字を表すのがdouble型である。 Main.java double number = 3.14; System.out.println(number); コンソール 3.14 型変換 Javaでは「+」などで文字列を連結させるときは同じデータ型同士でないといけないため、違うデータ型同士の場合は、同じデータ型に合わせる必要がある。 その方法として、「自動型変換」と「手動型変換」がある。 自動型変換 自動型変換の例として、以下のようにString型とint型を足すと、int型が自動でString型に変換される。 Main.java System.out.println("佐藤さんは" + 23 + "歳です"); // 「"佐藤さんは" + "23" + "歳です"」のようにString型に変換される ※数値の自動型変換の場合は、注意が必要である int型同士の計算はint型の結果になり、double型同士の計算はdouble型の結果になってしまう。 Main.java System.out.println(5 / 2); // 2 System.out.println(5.0 / 2.0); // 2.5 int型とdouble型の計算は、double型の結果になる。 Main.java System.out.println(5.0 / 2); // 2.5 // 「5.0 / 2.0」 手動型変換 変数に数字を格納している場合などで、強制的に型変換したいときは、「キャスト」を使う。 (変換したいデータ型)値 Main.java int number1 = 13; int number2 = 4; System.out.println((double)number1 / number2); // 3.25 // number1の値とnumber2の値がdouble型に変換される
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む