Todoのまとめ
・Todoサービスのまとめ
Dependency Injection: 依存性の注入
・thymeleaf(たいむりーふ)の依存
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
・Hibernateを使えるようになるための依存
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
・データベースの連結の依存
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
・YAMLでデータベースの設定
spring:
datasource:
url: jdbc:mysql://localhost:3306/todo?characterEncoding=UTF-8&serverTimezone=JST
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: root
jpa:
database: MySQL
show-sql: true
hibernate:
naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy
・画面遷移の設定
ボタンを押すと、指定画面に遷移しもす。
@Controller
public class PageController {
@RequestMapping("/other")
public String other() {
return "redirect:/";
}
@RequestMapping("/jump_to_add")
public String add() {
return "redirect:/add";
}
@RequestMapping("/edit/other")
public String delete() {
return "redirect:/";
}
}
・時間の取得
Controllerの最初定義すると、時間の更新はサーバの起動時間になってしまいました。
ですから、新しいクラスを作成します。
public class Get {
public static String time() {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(timestamp);
return time;
}
}
・Todo画面
repository.findAllは全てのデータを取得します。
そして、mav.addObjectで値を保存します。
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(@ModelAttribute TodoData tododata, ModelAndView mav) {
mav.setViewName("index");
Iterable<TodoData> list = repository.findAll();
mav.addObject("datalist", list);
return mav;
}
追加画面へ遷移します。
@RequestMapping(value = "/add", method = RequestMethod.GET)
public ModelAndView add(ModelAndView mav) {
mav.setViewName("add");
return mav;
}
Getクラスで時間をもらって、時間を設定して、データを保存します。
@RequestMapping(value = "/add", method = RequestMethod.POST)
@Transactional(readOnly = false)
public ModelAndView upload(@ModelAttribute TodoData tododata, ModelAndView mav) {
tododata.setCreatedDate(Get.time());
tododata.setUploadDate(Get.time());
repository.saveAndFlush(tododata);
return new ModelAndView("redirect:/");
}
編集画面に遷移して、テキストのIDを検索して、検索結果を保存します。
@RequestMapping(value = "/edit/{todoid}", method = RequestMethod.GET)
public ModelAndView edit(@ModelAttribute TodoData tododata, @PathVariable int todoid, ModelAndView mav,
String created_date, String user_id) {
mav.setViewName("edit");
Optional<TodoData> data = repository.findById*1;
return mav;
}
Getクラスで時間をもらって、時間を設定して、データを保存します。
@RequestMapping(value = "/edit", method = RequestMethod.POST)
@Transactional(readOnly = false)
public ModelAndView update(@ModelAttribute TodoData tododata, ModelAndView mav) {
tododata.setUploadDate(Get.time());
repository.saveAndFlush(tododata);
return new ModelAndView("redirect:/");
}
*1:long) todoid);
mav.addObject("formModel", data.get(
Spring 13
・複数削除の画面を現します。
public static String todo_text(TodoData mydata) {
// get todoID & todoText
String multiple = mydata.getMultiple();
multiple = multiple.replaceAll(",", "");
// convert to String array
String array_string = multiple.split("&split;%");
//put todoText to new array
int counter = array_string.length / 2;
String array_long = new String[counter];
int c = 1;
for (int i = 0; i < counter; i++) {
array_long[i] = array_string[c];
c = c + 2;
}
return array_long;
}
public static Long todo_id(TodoData mydata) {
// get todoID & todoText
String multiple = mydata.getMultiple();
// convert to String array
String array_string = multiple.split("&split;%");
// convert to long array
// method needs the long value
int counter = array_string.length / 2;
Long array_long = new Long[counter];
int c = 0;
for (int i = 0; i < counter; i++) {
array_long[i] = Long.valueOf(array_string[c]);
c = c + 2;
}
return (Long[]) array_long;
}
・完了ボタンを追加しました。
<script th:inline="javascript">
function changeUnderline(todoID) {
var btn_obj = document.getElementById(todoID + "id");
var text_obj = document.getElementById(todoID + "text");
if (text_obj.style.textDecoration == "line-through") {
text_obj.style.textDecoration = "none";
btn_obj.value = "完了";
} else {
text_obj.style.textDecoration = "line-through";
btn_obj.value = "未完了";
}
}
Spring 12
・複数削除機能を追加しました。
TodoIDの型をStringに変換するなら、複数の値をもらえるようになりましたが、
削除のメソッドを実行する時にバグになってしまいました。
ですから、新しいColumnを作成しました。
このColumnは何も保存していません。
(DataBaseと同じクラスですから、DataBaseで新しいColumnを作成しなければなりません。)
別のクラスを作成するなら、DataBaseで新しいColumnを作成するのは、
必要がなくなると思います。
複数TodoIDを受けるために、DataBaseで新しいColumnを作成しました。
TodoData.java
@Column(nullable = true)
private String multiple;
public String getMultiple() {
return multiple;
}
public void setMultiple(String multiple) {
this.multiple = multiple;
}
メソッドを使えるために、Stringの型からLongの型に変換しました。
MultipleDelete.java
public static Long todo_id(TodoData mydata) {
//get todoID
String multiple = mydata.getMultiple();
//convert to String array
String array_string = multiple.split(",");
//convert to long array
//method needs the long value
Long array_long = new Long[array_string.length];
for (int i = 0; i < array_string.length; i++) {
array_long[i] = Long.valueOf(array_string[i]);
}
//return value
return (Long) array_long;
}
複数削除の実行
TodoController.java
public ModelAndView removeconfirm(TodoData mydata,ModelAndView mav) {
LongtodoID = MultipleDelete.todo_id(mydata);
for(long delete_counter : todoID) {
repository.deleteById(delete_counter);
}
}
・日時の型の変換
変換したの日時をHTMLに渡します。
TodoController.java
public ModelAndView index(@ModelAttribute("formModel") TodoData mydata, ModelAndView mav) {
mav.setViewName("index");
Iterable<TodoData> list = repository.findAll();
ArrayList<String> Convert_Date = new ArrayList<>();
Convert_Date = DateConvert.Date(list,Convert_Date);
mav.addObject("datalist", list);
mav.addObject("Date",Convert_Date);
return mav;
}
日時の変換です。
DateConvert.java
public static ArrayList<String> Date(Iterable<TodoData> list,ArrayList<String> Convert_Date) {
for(TodoData s : list){
String upload_date = s.getUploadDate();
upload_date = upload_date.replaceFirst("(?i)(-)", "年");
upload_date = upload_date.replaceFirst("(?i)(-)", "月");
upload_date = upload_date.replaceFirst("(?i)( )", "日");
upload_date = upload_date.substring(0, 16);
int YEAR = Integer.parseInt(upload_date.substring(0, 4));
int MONTH = Integer.parseInt(upload_date.substring(5, 7));
int DATE = Integer.parseInt(upload_date.substring(8, 10));
MONTH = MONTH - 1;
DATE = DATE - 1;
String week = new String[7];
week[0] = "日";
week[1] = "月";
week[2] = "火";
week[3] = "水";
week[4] = "木";
week[5] = "金";
week[6] = "土";
Calendar YEAR_MONTH_DATE = Calendar.getInstance();
YEAR_MONTH_DATE.set(Calendar.YEAR, YEAR);
YEAR_MONTH_DATE.set(Calendar.MONTH, MONTH);
YEAR_MONTH_DATE.set(Calendar.DAY_OF_MONTH, DATE);
int DAY_OF_WEEK = YEAR_MONTH_DATE.get(Calendar.DAY_OF_WEEK);
upload_date = upload_date.substring(5, 11) + "(" + week[DAY_OF_WEEK] + ")" + upload_date.substring(11, 16);
Convert_Date.add(upload_date);
}
return Convert_Date;
}
Spring 12
・H2のデータ
保存することができますが、プロジェクトを再起動する時にデータを消してしまいました。
テーブルが突然なくなった状況もあります。
・データをprivateで定義することができません。
原因:Springの使い方ので、underlineを使えません。(DataBaseから値をもらうクラス)
・URLが疑問符を付いています。
template
<a href="edit.html" th:href="@{/edit/(${obj.todoID})">profile</a>
結果:
localhost:8080/edit/?123 (123はobj.todoID)
疑問符を使いたくない場合
<a href="edit.html" th:href="@{/edit/} + ${obj.todoID}">
結果:
localhost:8080/edit/123 (123はobj.todoID)
Spring 11
・HSQLDBのデータが表示されません。
・新しいプロジェクト作成(H2と接続)
application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:tcp://localhost/c:/workspace/JDBC/demo
spring.datasource.username=username
spring.datasource.password=password
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
@Service
このクラスをサービスとして登録するためのアノテーションです。
・AjaxでMyDataを取り出し、表示させます。
ページロード時にAjax通信します。
$(document).ready(function(){
var num = /*[[${param.id[0]}]]*/;
$.get("/rest/" + num, null, callback);
});
Ajax通信後の処理
function callback(result){
$('#obj').append('<li>id: ' + result.id + '</li>');
$('#obj').append('<li>name: ' + result.name + '</li>');
$('#obj').append('<li>mail: ' + result.mail + '</li>');
$('#obj').append('<li>age: ' + result.age + '</li>');
$('#obj').append('<li>memo: ' + result.memo + '</li>');
}
XMLでデータを取得します。
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
MyData.java
import javax.xml.bind.annotation.XmlRootElement:
@XmlRootElement
ApplicationArguments
アプリケーションが実行された時に渡された引数を管理します。
getNonOptionArgs
アプリケーション実行時の引数をListとして取り出せます。
・Beanクラスを作成して、Beanを登録して利用します。
public class MyDataBean {
@Autowired
MyDataRepository repository;
public String getTableTagById(Long id){
Optional<MyData> opt = repository.findById(id);
MyData data = opt.get();
String result = "<tr><td>" + data.getName()
+ "</td><td>" + data.getMail() +
"</td><td>" + data.getAge() +
"</td><td>" + data.getMemo() +
"</td></tr>";
return result;
}
}
MyBootAppConfig.java
@Configuration
public class MyBootAppConfig {
@Bean
MyDataBean myDataBean(){
return new MyDataBean();
}
}
IDによって表示します。
@Autowired
MyDataBean myDataBean;
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView indexById(@PathVariable long id,
ModelAndView mav) {
mav.setViewName("pickup");
mav.addObject("title","Pickup Page");
String table = "<table>"
+ myDataBean.getTableTagById(id)
+ "</table>";
mav.addObject("msg","pickup data id = " + id);
mav.addObject("data",table);
return mav;
}
・ページネーション
データの一部分だけを取り出して、表示します。
Repository
public Page<MyData> findAll(Pageable pageable);
Controller
@RequestMapping(value = "/page", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav, Pageable pageable) {
mav.setViewName("index");
mav.addObject("title","Find Page");
mav.addObject("msg","MyDataのサンプルです。");
Page<MyData> list = repository.findAll(pageable); //●
mav.addObject("datalist", list);
return mav;
}
表示する方:localhost:8080/page?size=2&page=0
・Thymeleafの独自タグを作成しました。
AttributeTagProcessorクラスを使います。
ITemplateContext
テンプレートのコンテキストを扱います。
IProcessableElementTag
エレメントタグを扱うクラスです。
AttributeName
属性名を扱うクラスです。
IElementTagStructureHandler
エレメントの構造をハンドリングします。
Spring 10
エンティティの連携
・HeidiSQLに連結することができません。
org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: java.sql.SQLSyntaxErrorException: Table 'test_01.mydata_msgdatas' doesn't exist
・H2やHSQLDBで実行します。
HSQLDB
1.C:\Users\admin\Downloads\hsqldb-2.4.1\hsqldb\bin に移動して、runServer.batを実行します。(閉じると、実行できません。)
2.CMDで開いて、C:\Users\admin\Downloads\hsqldb-2.4.1\hsqldb\data に移動します。
3.>java -cp ..\lib\hsqldb.jar org.hsqldb.util.DatabaseManager 入力します。
DataBase配置
mydata
CREATE TABLE TEST_TABLE (
id INTEGER NOT NULL IDENTITY,
name VARCHAR(256),
mail VARCHAR(256),
age INTEGER,
memo VARCHAR(200)
)
msgdata
CREATE TABLE TEST_TABLE (
id INTEGER NOT NULL IDENTITY,
title VARCHAR(256),
message VARCHAR(256),
)
Spring配置
application.properties
spring.datasource.url=jdbc:hsqldb:file:./db/testdb;shutdown=true
spring.jpa.hibernate.ddl-auto=update
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</dependency>
実行結果:成功
H2
会ったバグ
java. sql.SQLTransientConnectionException: java.net. ConnectException: Connection refused: connect
解決できませんでしたが、HSQLDBでDateBaseを作ったら、突然使えるようになりました。
Spring 09
・メソッドチェーン
メソッドの呼び出しを連続して記述する手法です。
例:
entityManager.createQuery(qstr).setParameter("fid", fid)
.setParameter("fname", "%" + fstr + "%").setParameter("fmail", fstr + "@%")
@NamedQuery
クエリー文に名前を付けてエンティティクラスに用意しておきます。
@NamedQueries
複数のクエリー文を作りたい時、このアノテーションを使って全てをまとめることができます。
・Criteria APIによる検索
1.CriteriaBuilderの取得
CriteriaBuilderインスタンスの用意です。
CriteriaBuilder builder=《EntityManager》.getCriteriaBuilder();
2.CriteriaQueryの作成
特定のエンティティにアクセスするには、そのエンティティのclassプロパティを引数に指定します。
CriteriaQuery<エンティティ> 変数 = 《CriteriaBuilder》.createQuery(エンティティ.class);
3.Rootの取得
CriteriaBuilderのformメソッドでRootを取得します。引数には、検索するエンティティのClassを指定します。
Root<エンティティ> 変数 = 《CriteriaBuilder》.from(エンティティ.class);
4.createQueryして結果を取得
createQueryでQueryを生成し、getResultListで結果のListを取得します。
List<エンティティ> 変数 = (List<エンティティ>)《EntityManager》.createQuery(《CriteriaBuilder》).getResultList();
全要素の検索
@Override
public List<MyData> getAll() {
List<MyData> list = null;
CriteriaBuilder builder =
entityManager.getCriteriaBuilder();
CriteriaQuery<MyData> query =
builder.createQuery(MyData.class);
Root<MyData> root = query.from(MyData.class);
query.select(root);
list = (List<MyData>)entityManager
.createQuery(query)
.getResultList();
return list;
}
名前の検索
@Override
public List<MyData> find(String fstr){
CriteriaBuilder builder =
entityManager.getCriteriaBuilder();
CriteriaQuery<MyData> query =
builder.createQuery(MyData.class);
Root<MyData> root =
query.from(MyData.class);
query.select(root)
.where(builder.equal(root.get("name"), fstr));
List<MyData> list = null;
list = (List<MyData>) entityManager
.createQuery(query)
.getResultList();
return list;
}
CriteriaBuilder
CriteriaQueryのオブジェクトを作成します。
CriteriaQuery
クエリーに指定したアイテムを返します。
以前に指定された選択がある場合は、置き換えます。
Root
ルートに対応するメタモデルエンティティを返します。
昇順のorderを得ます
《CriteriaBuilder》.asc(《Expression》);
降順のorderを得ます
《CriteriaBuilder》.desc(《Expression》);
指定の位置から取得します。
Query 変数 =《Query》.setFirstResult(《int》)
指定の個数を取得します。
Query 変数 =《Query》.setMaxResult(《int》)
・エンティティの連携
@OneToMany
1つのエンティティに対して、もう一方のエンティティの複数が対応します。
@ManyToOne
複数のエンティティに対して、もう一方のエンティティの1つだけが対応します。
@ManyToMany
複数のエンティティに対して、他方の複数のエンティティが対応する関係です。