- 投稿日:2020-03-22T13:08:23+09:00
Java for All!みんなのJavaを読みました #minjava
みんなのJavaを読みました!
著者のJVMに(詳しく)なりたい人(@jyukutyo)から献本頂きました。
ありがとうございます!
ちょうど読みたかった本なので、とても嬉しかったです。どんな本?
Javaの今を知る本です。Java 5で導入されたジェネリック、Java 8で導入されたラムダと、ここまでJavaの技術動向に追随してきた方でも、Java 9以降の変化の速さについていけてないエンジニアも多いかと思います。
Java 9のリリース後から、半年に一度、3月、9月にメジャーバージョンを上げる方針になりました。
これに伴い、進化の遅れからくるレガシー感を払しょくし、Javaは正常な進化を再び歩み始めました。
昔のJavaで知識が止まっている方は、この本を読むことで、驚くべきJavaの進化と可能性を発見できるかと思います。どれくらいで読める?
各分野に詳しい著名人が、それぞれの得意分野について記述しています。
僕は本を読むのが遅いほうですが、集中すれば、1章あたり2時間もあれば読めるくらいのボリュームでした。6章あるので、読むのが速い方なら1日で読めそうですね。各章を読み、気になる技術はそこから深追いできる構成になっています。
これらの内容をネットで集めようとすると大変です。それがコンパクトに纏まっており、非常に効率よく知識を仕入れることが出来ました。どんな人にお勧めか?
次のような方にお勧め出来るかと思います。
- 最近のJava動向を知りたい方
- どのJDKディストリビューションを選択するか迷っている方
- サーバレスやマイクロサービスに興味のある方
- 新しい技術に興味のある方
一方で、これからJavaを勉強しようという方向きではないので、ご注意ください。
各章の感想
第1章 進化するJava!Java9から14までのJavaの変化を紹介
Java9から14までの言語仕様や標準ライブラリの変化について紹介されています。
僕のお気に入りの技術変化は次のとおりです。
- ローカル変数型推論
- インタフェースでのprivateメソッド
- Switch式
- シールド型
- パターンマッチング
- 新しいHTTP Client
他にも沢山の技術変化が紹介されています。今後期待するのは、Project Loomで開発が進められている軽量スレッドです。
長年Javaを用いて開発してる僕でも、Java9以降の変化の速さにはびっくりです。
「はじめに」に書いてる、『Javaはみんなで作るものになりました。』
がまさしくと思える出だしの章でした。
第2章 これでもう迷わない!?JDKディストリビューション徹底解説
Oracle JDK/JREのライセンス変更の発表で、一時「Javaが有償化!?」などの混乱を招きました。
この混乱は有志の努力のかいもあり、一応の収まりは見せたように思います。一方で「どのJDKディストリビューションを使うのがいいか?」については、各現場のエンジニアの関心ごとの一つだと思います。この章は、OpenJDKとJDKディストリビューションの歴史から説明しており、「どのJDKディストリビューションを採用するか」を判断する上で、今日本一纏まってる情報だと思います。
また、今までOracleが如何にJavaに貢献し、今後も貢献し続けるかがわかる章でした。Javaを活用する現場のエンジニアは、一度は目に通しておいたほうがいいでしょう。
第3章 Jakarta EEとは!?新しいEnterprise Javaの近況
3章は「新しいEnterprise Java」です。
新機能の紹介というより、Jakarta EEに至るまでの歴史を学べる章です。
現場では、Java EEで作成されたシステムが今なお運用されており、今後のエンハンスを考える上で、この章の知識があるといいでしょう。
私も昔、JAX-RSでモバイル向けAPI作った記憶が蘇りました。
今はJakarta RESTful Web Servicesと呼ぶそうです。知らなかった!第4章 Javaでマイクロサービス!MicroProfileの紹介
マイクロサービスの為のコミュニティ標準、MicroProfileの章です。
- コミュニティ主導
- 仕様より動作する実装を優先
- 頻繁かつ定期的なリリース
という方針が時流にあってますね。
Long Running ActionsとかGraphQLなど、今後の仕様策定も気になります。
この後の第6章で出てくる、Java軽量フレームワーク「Quarkus」を知る上でもこの章の知識が役立つと思います。第5章 今一番熱い!?GraalVMの紹介
次世代Javaの可能性を一気に広げるGraalVMのお話です。
全ページに渡り、なんか愛を感じますw「GraalVMってJavaでネイティブイメージを生成する技術でしょ?」
という知識の方は、ぜひこの章をご覧ください。
GraalVMの本当のすごさを知ることになるかと思います。
あらゆる言語がGraalVM上で動き、様々な環境でネイティブイメージのJavaが動く未来があるかも。
素晴らしいですね!第6章 Lambdaで使えないとか言わせない!サーバレス対応の[新世代]Java軽量フレームワーク
マイクロサービス、サーバレスといった背景から出てきた、次世代軽量Javaフレームワークの紹介です。
Micronaut/Quarkus/Helidonといった、次世代に活躍するかもしれないフレームワークの特徴を、それぞれ比較して知ることが出来ます。Javaフレームワークについては、Spring Bootの1強時代になるかと思いましたが、ここにきて有力な対抗馬が出てきました。面白いですね!
僕はQuarkusが好みかな?
どこかで時間が取れれば、追っていきたいと思います。そのうえで、本章はその導入役として役立つ内容だと感じました。まとめ
私自身、Java 8あたりで知識が止まっていたので、この書籍が非常に役立ちしました。
最近はアプリケーションを開発する技術も多方面に渡り、一つの技術だけを深く追っていくのは大変です。こういう時、本書のような纏まった情報があると非常に助かります。著者のみなさん、本当にありがとうございました。
- 投稿日:2020-03-22T12:18:37+09:00
Javaでログイン機能を作ってみた
作った動機
訓練校でアプリを8人チームで制作することになったのだが、機能要件にログイン機能が必須だった。
登録したロールによって表示できるページを分けたいが、やり方がいまいちわからなかった。
3連休だし作ってみよ!機能
- 新規登録。
- ログイン、ログアウト。
- 管理者とユーザーでロール分け。
- 管理者には管理者ページしか表示されない。
- ユーザーにはユーザーページしか表示されない。
- ログインしてない場合はログイン画面と新規登録画面へ誘導。
よかったこと
4時間くらいで作れた。
3か月前なら3~5倍くらい時間がかかっていたと思う。
成長してるんやなあ。環境
Java version 13.0.1
mysql 8.0DAO
AccountDAO.javapackage dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import model.AccountBeans; public class AccountDAO { // データベース接続に使用する情報 final String jdbcId = "root"; final String jdbcPass = "password"; final String jdbcUrl = "jdbc:mysql://localhost:3306/test?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=JST"; // ログインアカウントを探す public AccountBeans findAccount(AccountBeans ab) { // 戻り値の用意 AccountBeans returnAb = new AccountBeans(); // データベースへ接続 try (Connection con = DriverManager.getConnection(jdbcUrl, jdbcId, jdbcPass)) { String sql = "SELECT loginId, pass, name, roleId FROM account WHERE loginId = ? AND pass = ?"; PreparedStatement ps= con.prepareStatement(sql); ps.setString(1, ab.getLoginId()); ps.setString(2, ab.getPass()); ResultSet rs = ps.executeQuery(); if (rs.next()) { // 見つかったアカウント情報を戻り値にセット returnAb.setLoginId(rs.getString("loginId")); returnAb.setPass(rs.getString("pass")); returnAb.setName(rs.getString("name")); returnAb.setRole(rs.getInt("roleId")); } else { // アカウントがなければnullを返す return null; } } catch (SQLException e) { e.printStackTrace(); return null; } return returnAb; } }AccountRegisterDAO.javapackage dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import model.AccountBeans; public class AccountRegisterDAO { // データベース接続に使用する情報 final String jdbcId = "root"; final String jdbcPass = "password"; final String jdbcUrl = "jdbc:mysql://localhost:3306/test?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=JST"; public AccountRegisterDAO(AccountBeans ab) { try (Connection con = DriverManager.getConnection(jdbcUrl, jdbcId, jdbcPass)) { String sql = "INSERT INTO account (loginId, pass, name, roleId) VALUES (?, ?, ?, ?)"; PreparedStatement ps= con.prepareStatement(sql); ps.setString(1, ab.getLoginId()); ps.setString(2, ab.getPass()); ps.setString(3, ab.getName()); ps.setInt(4, ab.getRole()); int r = ps.executeUpdate(); if(r != 0) { System.out.println("新規登録成功!"); } else { System.out.println("新規登録失敗( ノД`)シクシク…"); } } catch (SQLException e) { e.printStackTrace(); } } }servlet
AccountCheck.javapackage servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import model.AccountBeans; /** * Servlet implementation class AccountCheck */ @WebServlet("/AccountCheck") public class AccountCheck extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public AccountCheck() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // セッションからログイン情報を取得 HttpSession session = request.getSession(); AccountBeans ab = (AccountBeans) session.getAttribute("account"); // ロールでフォワード先を振り分ける if(ab.getRole() == 1) { RequestDispatcher rd = request.getRequestDispatcher("admin.jsp"); rd.forward(request, response); } else if(ab.getRole() == 2) { RequestDispatcher rd = request.getRequestDispatcher("user.jsp"); rd.forward(request, response); } else { RequestDispatcher rd = request.getRequestDispatcher("error.jsp"); rd.forward(request, response); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }AccountRegister.javapackage servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import dao.AccountRegisterDAO; import model.AccountBeans; /** * Servlet implementation class AccountRegister */ @WebServlet("/AccountRegister") public class AccountRegister extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public AccountRegister() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); String loginId = request.getParameter("loginId"); String pass = request.getParameter("pass"); int role = Integer.parseInt(request.getParameter("role")); // register.jspから受け取った値をビーンズにセット AccountBeans ab = new AccountBeans(); ab.setName(name); ab.setLoginId(loginId); ab.setPass(pass); ab.setRole(role); // アカウントをDBに登録 AccountRegisterDAO ard = new AccountRegisterDAO(ab); // セッションにアカウント情報を保存 HttpSession session = request.getSession(); session.setAttribute("account", ab); RequestDispatcher rd = request.getRequestDispatcher("registerSuccess.jsp"); rd.forward(request, response); } }AccountSearch.javapackage servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import dao.AccountDAO; import model.AccountBeans; /** * Servlet implementation class AccountDAO2 */ @WebServlet("/AccountSearch") public class AccountSearch extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public AccountSearch() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String loginId = request.getParameter("loginId"); String pass = request.getParameter("pass"); // login.jspから受け取ったログインIDとpassをビーンズにセット AccountBeans ab = new AccountBeans(); ab.setLoginId(loginId); ab.setPass(pass); // アカウントの有無を検索 // 検索したアカウント情報を取得 AccountDAO ad = new AccountDAO(); AccountBeans returnAb = ad.findAccount(ab); if(returnAb != null) { // セッションにアカウント情報&ロールを登録 HttpSession session = request.getSession(); session.setAttribute("account", returnAb); RequestDispatcher rd = request.getRequestDispatcher("loginSuccess.jsp"); rd.forward(request, response); } else { RequestDispatcher rd = request.getRequestDispatcher("error.jsp"); rd.forward(request, response); } } }Logout.javapackage servlet; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class Logout */ @WebServlet("/Logout") public class Logout extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Logout() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub HttpSession session = request.getSession(); session.invalidate(); RequestDispatcher rd = request.getRequestDispatcher("login.jsp"); rd.forward(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }filter
Filter.javapackage filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; /** * Servlet Filter implementation class Filter */ @WebFilter("/*") public class Filter implements javax.servlet.Filter { /** * Default constructor. */ public Filter() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub // place your code here request.setCharacterEncoding("UTF-8"); // pass the request along the filter chain chain.doFilter(request, response); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }JavaBeans
AccountBeans.javapackage model; import java.io.Serializable; public class AccountBeans implements Serializable { private static final long serialVersionUID = 1L; private String loginId; private String pass; private String name; private int role; public String getLoginId() { return loginId; } public void setLoginId(String loginId) { this.loginId = loginId; } public String getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getRole() { return role; } public void setRole(int role) { this.role = role; } }JSP
admin.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>管理者ページ</title> </head> <body> ここは管理者用のページです。<br> <c:choose> <c:when test="${account.role == 1 }"> 登録内容の確認。 <p>ログインID:<c:out value="${account.loginId }"></c:out></p> <p>パスワード:<c:out value="${account.pass }"></c:out></p> <p> 名前:<c:out value="${account.name }"></c:out></p> <p> ロール:管理者</p> <p><a href="/login/Logout"><button type="button" >ログアウト</button></a></p> <a href="user.jsp"><button type="button" >ユーザーページへ</button></a> </c:when> <c:when test="${account.role == 2 }"> <a href="user.jsp">ユーザーページへ</a> </c:when> <c:otherwise> <a href="login.jsp">ログインページへ</a> </c:otherwise> </c:choose> </body> </html>error.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> ログインに失敗しました。<br> <a href="login.jsp"><button>ログインページへ</button></a> </body> </html>login.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ログイン画面</title> </head> <body> <form action="/login/AccountSearch" method="post"> ユーザーID:<input type="text" name="loginId" required><br> パスワード:<input type="password" name="pass" required><br> <input type="submit" value="ログイン"><br> </form> <p> アカウント登録がお済みでない方はこちらへ↓<br> <a href="register.jsp"><button>新規登録</button></a> </p> </body> </html>loginSuccess.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ログイン成功</title> </head> <body> ログインが成功しました! <p><a href="/login/AccountCheck"><button type="button" name="aaa" >ユーザー or 管理者ページへ</button></a></p> </body> </html>register.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>新規登録</title> </head> <body> <form action="/login/AccountRegister" method="post"> <p>すべて入力してください</p> <p> <input type="radio" name="role" value="1">管理者で登録する <input type="radio" name="role" value="2" checked>ユーザーで登録する </p> 名前:<input type="text" name="name" required><br> ユーザーID:<input type="text" name="loginId" required><br> パスワード:<input type="password" name="pass" required><br> <input type="submit" value="登録"><br> </form> </body> </html>registerSuccess.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登録完了</title> </head> <body> 新規登録が完了しました! <p><a href="/login/AccountCheck"><button type="button" name="aaa" >ユーザー or 管理者ページへ</button></a></p> </body> </html>user.jsp<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ユーザー情報</title> </head> <body> ここはユーザーページです。<br> <c:choose> <c:when test="${account.role == 2 }"> 登録内容の確認。 <p>ログインID:<c:out value="${account.loginId }"></c:out></p> <p>パスワード:<c:out value="${account.pass }"></c:out></p> <p> 名前:<c:out value="${account.name }"></c:out></p> <p> ロール:ユーザー</p> <p><a href="/login/Logout"><button type="button" >ログアウト</button></a></p> <a href="admin.jsp"><button type="button" >管理者ページへ</button></a> </c:when> <c:when test="${account.role == 1 }"> <a href="admin.jsp">管理者ページへ</a> </c:when> <c:otherwise> <a href="login.jsp">ログインページへ</a> </c:otherwise> </c:choose> </body> </html>テーブル構成
- 投稿日:2020-03-22T11:47:50+09:00
java コールバックパターン
javaでコールバックパターンの簡単なサンプル
文字列を
・CamelCase → snake_case
・小文字 → 大文字
した後に表示する処理を例にやってみるコールバックパターンを用いない場合
NoCallbackPattern.javapublic class NoCallbackPattern { /** * CamelCaseからsnake_caseへ変換 */ private String camelToSnake(String input) { return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, input); } /** * 小文字から大文字へ変換 */ private String capitalize(String input) { return input.toUpperCase(); } /** * 変換して表示 */ public void print(String input) { System.out.println(capitalize(camelToSnake(input))); } }Main.javapublic class Main { public static void main(String[] args) { NoCallbackPattern noCallbackPattern = new NoCallbackPattern(); noCallbackPattern.print("replaceString"); } }コールバックパターンで書いた場合
CallbackPattern.javapublic class CallbackPattern { private List<MyFilter> myFilters; public CallbackPattern(List<MyFilter> myFilters) { this.myFilters = myFilters; } public void print(String input) { String output = input; for (MyFilter myFilter : myFilters) { output = myFilter.replace(output); } System.out.println(output); } }MyFilter.javapublic interface MyFilter { String replace(String input); }CamelToSnake.javapublic class CamelToSnake implements MyFilter { @Override public String replace(String input) { return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, input); } }Capitalize.javapublic class Capitalize implements MyFilter { @Override public String replace(String input) { return input.toUpperCase(); } }Main.javapublic class Main { public static void main(String[] args) { List<MyFilter> filters = Arrays.asList(new CamelToSnake(), new Capitalize()); CallbackPattern callbackPattern = new CallbackPattern(filters); callbackPattern.print("replaceString"); } }コールバックパターンを用いて書いた方が、printメソッドがMyFilterインターフェースにしか依存していないため、変換処理を追加する場合にCallbackPatternクラスの修正が必要ないことがわかります