発表用資料の作成
PowerPointのテンプレートをコピーして使用する。
\\kgakusei1\share\澤田\発表資料.pptx
チーム開発の感想などは、Backlogで担当した課題を見れば思い出しやすい。
Webアプリの講義内容と関連資料など
PowerPointのテンプレートをコピーして使用する。
\\kgakusei1\share\澤田\発表資料.pptx
チーム開発の感想などは、Backlogで担当した課題を見れば思い出しやすい。
基本機能が動作するようにがんばりましょう!
機能の単位はロバストネス図で考えること。
発表用のパワポ作成の課題を誰かに割り当てる
(テンプレートを用意するので必要事項を記入する)
発表する機能の動作確認。
1現目はチーム内でパワポの確認とデモ内容の確認。
2現目は発表。
たとえばidをURLに含める場合のJSP記述方法。
<a href="hoge?id=${obj.id}">${obj.title}</a>
ログアウトを実行したい場合、spring-security.xml に以下の設定をする。
<sec:http auto-config="true"> <intercept-url pattern="/**" access="ROLE_USER" /> <sec:form-login login-page="/login.jsp" default-target-url="/home" authentication-failure-handler-ref="authenticationFailureHandler" /> <sec:logout logout-url="/logout" logout-success-url="/" invalidate-session="true" delete-cookies="JSESSIONID" /> </sec:http> <beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/login.jsp?error=true"/> <beans:property name="useForward" value="true"/> </beans:bean>
ログインしたユーザーを取得するには、コントローラの引数に Principal を追加する。
ここでは、追加した Princical から getName()メソッドでユーザー名を取得し、addAttribute() で name に値を設定している。
@RequestMapping(value = "/home", method = RequestMethod.GET) public String home(Model model, Principal p) { model.addAttribute("name", p.getName()); return "home"; }
Userインスタンスの取得
Principal から取得できるのは名前だけなので、詳細な情報を取得するには、名前をキーにしてUsersテーブルから取得する必要がある。
Usersテーブルから名前をキーにして取得するために、DAOにメソッド定義 findByName() を追加する。
UserDao.java
public interface UserDao<T> { public List<T> getAll(); public T findById(long id); public T findByName(String name); public void add(T data); public void update(T data); public void delete(T data); public void delete(long id); }
UserDaoImpl で、検索機能を実装する。
UserDaoImpl.java
public class UserDaoImpl implements UserDao<User> { private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistenceUnit"); public List<User> getAll() { EntityManager manager = factory.createEntityManager(); CriteriaBuilder builder = manager.getCriteriaBuilder(); CriteriaQuery<User> query = builder.createQuery(User.class); Root<User> root = query.from(User.class); query.select(root); List<User> list = null; try { list = manager.createQuery(query).getResultList(); } catch (NoResultException e) { // } return list; } public User findById(long id) { EntityManager manager = factory.createEntityManager(); CriteriaBuilder builder = manager.getCriteriaBuilder(); CriteriaQuery<User> query = builder.createQuery(User.class); Root<User> root = query.from(User.class); query.select(root).where(builder.equal(root.get("id"), id)); User u = null; try { u = manager.createQuery(query).getSingleResult(); } catch (NoResultException e) { // } return u; } public User findByName(String name) { EntityManager manager = factory.createEntityManager(); CriteriaBuilder builder = manager.getCriteriaBuilder(); CriteriaQuery<User> query = builder.createQuery(User.class); Root<User> root = query.from(User.class); query.select(root).where(builder.equal(root.get("name"), name)); User u = null; try { u = manager.createQuery(query).getSingleResult(); } catch (NoResultException e) { // } return u; } public void add(User user) { EntityManager manager = factory.createEntityManager(); EntityTransaction transaction = manager.getTransaction(); transaction.begin(); User u = findById(user.getId()); if (u == null) { try { manager.persist(user); transaction.commit(); } catch (PersistenceException e) { transaction.rollback(); } manager.close(); } else { throw new PersistenceException("Duplicate user-id : " + u.getId()); } } public void update(User user) { EntityManager manager = factory.createEntityManager(); EntityTransaction transaction = manager.getTransaction(); transaction.begin(); try { manager.merge(user); transaction.commit(); } catch (PersistenceException e) { transaction.rollback(); } manager.close(); } public void delete(User user) { EntityManager manager = factory.createEntityManager(); EntityTransaction transaction = manager.getTransaction(); transaction.begin(); try { manager.remove(user); transaction.commit(); } catch (PersistenceException e) { transaction.rollback(); } manager.close(); } public void delete(long id) { delete(findById(id)); } }
共有データベースを配置するパソコンを決める。
そのパソコンで、server.properties を作成する。
作成する場所は、C:\Users\se3\db\hsqldb-2.3.2\hsqldb\data フォルダ。
server.properties
# Hsqldb Server cfg file. # See the HyperSQL Network Listeners chapter of the HyperSQL User Guide. # Each server.database.X setting defines a database "catalog". # I.e., an independent set of data. # Each server.database.X setting corresponds exactly to the jdbc:hsqldb:* # JDBC URL you would use if you wanted to get a direct (In-Process) # Connection to the catalog instead of "serving" it. server.database.0=file:db0/mydatabase server.dbname.0=mydatabase # I suggest that, for every file: catalog you define, you add the # connection property "ifexists=true" after the database instance # is created (which happens simply by starting the Server one time). # Just append ";ifexists=true" to the file: URL, like so: # server.database.0=file:db0/db0;ifexists=true # server.dbname.0 defaults to "" (i.e. server.dbname.n for n==0), but # the catalog definition n will be entirely ignored for n > 0 if you do not # set server.dbname.n. I.e. dbname setting is required for n > 0, though it # may be set to blank (e.g. "server.dbname.3=")
C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runServer.bat をダブルクリックして起動する。
コマンドプロンプトに次の出力があれば、データベースの作成に成功している。
C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin>cd ..\data [Server@24d46ca6]: [Thread[main,5,main]]: checkRunning(false) entered [Server@24d46ca6]: [Thread[main,5,main]]: checkRunning(false) exited [Server@24d46ca6]: Startup sequence initiated from main() method [Server@24d46ca6]: Loaded properties from [C:\Users\se3\db\hsqldb-2.3.2\hsqldb\data\server.properties] [Server@24d46ca6]: Initiating startup sequence... [Server@24d46ca6]: Server socket opened successfully in 15 ms. [Server@24d46ca6]: Database [index=0, id=0, db=file:db0/mydatabase, alias=mydata base] opened sucessfully in 484 ms. [Server@24d46ca6]: Startup sequence completed in 499 ms. [Server@24d46ca6]: 2015-11-16 11:12:14.474 HSQLDB server 2.3.2 is online on port 9001 [Server@24d46ca6]: To close normally, connect and execute SHUTDOWN SQL [Server@24d46ca6]: From command line, use [Ctrl]+[C] to abort abruptly
C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runManager.bat をダブルクリックして起動する。
接続のために以下の設定をして、OKすると接続できる。
Type : HSQL Database Engine Server URL : jdbc:hsqldb:hsql://localhost/mydatabase
他のパソコンから接続するには、パソコンのIPアドレスを調べる必要がある。
コマンドプロンプトを起動して ipconfig コマンドを実行して、IPアドレスを調べる。
C:\Users\se3>ipconfig Windows IP 構成 Wireless LAN adapter ワイヤレス ネットワーク接続: メディアの状態. . . . . . . . . . : メディアは接続されていません 接続固有の DNS サフィックス . . . : イーサネット アダプター ローカル エリア接続 2: 接続固有の DNS サフィックス . . . : IPv4 アドレス . . . . . . . . . . : 172.25.20.23 サブネット マスク . . . . . . . . : 255.255.0.0 デフォルト ゲートウェイ . . . . . : 172.25.1.254 イーサネット アダプター ローカル エリア接続 3: 接続固有の DNS サフィックス . . . : IPv4 アドレス . . . . . . . . . . : 192.168.56.1 サブネット マスク . . . . . . . . : 255.255.255.0 デフォルト ゲートウェイ . . . . . :
他のパソコンから接続する場合は、localhost の代わりにそのパソコンのIPアドレスを指定する。
C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runManager.bat をダブルクリックして起動する。
接続のために以下の設定をして、OKすると接続できる。
Type : HSQL Database Engine Server URL : jdbc:hsqldb:hsql://192.168.56.1/mydatabase
Onwerが複数のChildを持つ場合は、以下のようにエンティティを作成する。
Owner.java
@Entity public class Onwer { @Id @GeneratedValue(strategy = GenerationType.AUTO) @NutNull public long id; @OneToMany(cascade=CascadeType.ALL) @Column(nullable = false) private List<Child> children; // gettere/setter を用意 }
Child.java
@Entity public class Child { @Id @GeneratedValue(strategy = GenerationType.AUTO) @NutNull public long id; @ManyToOne @Column(nullable = false) private Owner owner; // getter/setter を用意 }
Onwerに複数のChildを追加した状態でエンティティを永続化すると、そのOwnerをDBから取り出したときは、追加した複数のChildが追加された状態で取り出せる。
機能を検討するときは、必要最小限の機能を先に作る。
たとえば、編集や削除を行う場合に、編集内容や削除の確認があったほうがいいと思った場合、まずは確認を行わないUIを作成する。
課題は以下のように作成する。
確認しないUIで作成して動かしてみる。
実際に使ってみて、確認が必要だと思ったら確認のUIを追加する。
pom.xml に以下の設定を追加する。
pom.xml
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>4.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.0.1.RELEASE</version> </dependency>
web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/application-config.xml</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-security.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- - Servlet that dispatches request to registered handlers (Controller implementations). --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/mvc-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
デフォルトでは「Click to Enter」とだけ表示している画面を、独自のトップページに修正しよう。
修正するファイルは、webapp の下にある index.jsp 。
Springでは、Spring Security によって、ログインなしでアクセスできるところと、ログインが必要なところを分類する。
ログインしていない状態でログインが必要なところにアクセスすると、自動的に標準のログインダイアログを表示する。
ログイン画面を標準のものと変えたいときは、spring-security.xml で、ログ引用のJSPを設定する。
Gitリポジトリを削除するには、Backlog の「プロジェクト設定」で Git を選択し、「編集」をクリックする。
そこで、リポジトリの削除ができる。
.gitignore ファイルに記述して、.gitignore をコミット/プッシュする。
プロジェクトエクスプローラ右上の▽をクリックし、「ビューのカスタマイズ」を選択する。
「.* リソース」のチェックをはずしてOKする。
ユーザーとユーザの権限を管理するためのテーブルを作成する。
CREATE TABLE users( user_id bigint NOT NULL identity, user_name varchar(50) NOT NULL, password varchar(50) NOT NULL, enabled tinyint NOT NULL, role varchar(100) NOT NULL );
テーブルにテスト用のユーザーを登録する。
INSERT INTO users ( user_name , password , enabled, role) VALUES ( 'taro', 'abcd' , 1, 'ROLE_USER' );
spring-security.xml を、データベースを使った認証をするように書き換える。
spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd"> <http pattern="/" security="none"/> <http pattern="/index.jsp" security="none"/> <http auto-config="true" > <intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> <form-login /> <logout /> </http> <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <beans:property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" /> <beans:property name="url" value="jdbc:hsqldb:hsql://localhost/mydatabase" /> <beans:property name="username" value="sa" /> <beans:property name="password" value="" /> </beans:bean> <!-- ユーザとROLEを定義 --> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="SELECT user_name, password, enabled FROM users WHERE user_name = ?" authorities-by-username-query="SELECT user_name, role FROM users WHERE user_name = ?" /> </authentication-provider> </authentication-manager> </beans:beans>