In Mybatis der O / R-Mapping-Flockenarbeit wird der in Mybatis bereitgestellte automatische Typkonvertierungsmechanismus: Behandelt Enum mit TypeHandler. Wir werden auch vorstellen, wie dynamisches SQL und seine Anwendung mit Spring MVC geschrieben werden.
Es gibt eine Spalte [^ 1], die "Flags" und "partitionierte Werte" behandelt, die wahrscheinlich in der Datenbank vorhanden sind, die von neu erstellten Systemen und Anwendungen verwendet wird, die bereits erstellt wurden, und der Bereich dieser Werte ist nahezu unverändert [^ 2]. ] ist. Da diese Werte häufig als Zeichenfolgentyp (CHAR oder VARCHAR) oder numerischer Typ behandelt werden, werden die Zeichenfolge und der numerische Wert zumindest in der Welt des Java-Codes nicht so behandelt, wie sie sind, und der Wertebereich ist Wenn es entschieden wurde, kann es per Aufzählung behandelt werden ...? Ist der Anfang.
In diesem Artikel haben wir den Vorgang mit den folgenden Versionen erstellt und bestätigt.
Es wird auf GitHub veröffentlicht.
https://github.com/A-pZ/mybatis-spring-enum-sample
Diesmal wurde eine Funktion eingeführt, die das Ergebnis der Suche in einer Tabelle zurückgibt, die ein bestimmtes Flag oder einen bestimmten Teilungswert verarbeitet.
Um kurz zu erklären, was implementiert werden soll
ist.
Dies ist die Definition der Tabelle, auf die dieses Mal verwiesen werden soll [^ 3].
Produkttabelle (Tabellenname: Artikel)
Spaltenname | Schimmel | Die Rolle der Spalte | Einschränkungen usw. |
---|---|---|---|
id | Numerischer Wert | Primärschlüssel, der das Produkt eindeutig definiert | Wert, der automatisch nummeriert werden soll |
name | String | Produktname | Produktnameの表示に使う |
status | String | Klassifizierung der Produktanzeige | 0:Kein Status 1:Für die Öffentlichkeit zugänglich 2:Nur für Mitglieder |
display | String | Produkte ein- / ausblenden | 0:Nicht anzeigen 1:zeigen |
Dieses Mal konzentrieren wir uns auf den dreistelligen Teilungswert, der durch den Status definiert wird, und auf das Flag, das von der Anzeige behandelt wird.
Erstellen Sie auf der Java-Seite eine Aufzählung für den Status und die Anzeige der beiden Spalten, die dieses Mal angezeigt werden. Da der Status "derjenige ist, der den Umfang der Produktoffenlegung bestimmt", benennen Sie ihn in ItemPublish um. Da display ein Binärwert ist, der bestimmt, ob angezeigt werden soll oder nicht, wird er im Allgemeinen auf TrueOrFalse gesetzt, damit er in anderen Spalten verwendet werden kann.
ItemPublish.java
import java.util.Arrays;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*Produktanzeigekategorie.
*/
@Getter
@AllArgsConstructor
public enum ItemPublish {
NONE("0"), PUBLISH("1"), MEMBER_ONLY("2"), NO_VALUE("");
private String value;
public static ItemPublish getDisplayStatus(String value) {
return Arrays.stream(values())
.filter(v -> v.getValue().equals(value))
.findFirst()
.orElse(NO_VALUE);
}
}
NO_VALUE ist definiert [^ 4], wenn ein Wert außerhalb des Bereichs angegeben wird, den der Divisionswert annehmen kann.
TrueOrFalse.java
@Getter
@AllArgsConstructor
public enum TrueOrFalse {
TRUE("1"), FALSE("0"), NONE("");
private String value;
TrueOrFalse(String value) {
this.value = value;
}
public static TrueOrFalse getTrueOrFalse(String input) {
return Arrays.stream(values())
.filter(v -> v.getValue().equals(input))
.findFirst().orElse(NONE);
}
}
Eine Aufzählung, die einen booleschen Wert definiert (1 für wahr, 0 für falsch). Andere Werte als 0 und 1 sind unerwartet, aber unerwartete Werte werden als NONE definiert.
Eine Implementierung, die die Datenbank abfragt. Spring MVC Repository und Service. Suchbedingungen werden in der ItemCondition-Klasse definiert, und ein Datensatz mit Suchergebnissen wird in der Item-Klasse definiert.
ItemRepository.java
mport java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
import serendip.spring.sample.mybatis.model.Item;
import serendip.spring.sample.mybatis.model.ItemCondition;
/**
*Produktsuch-Repository.
*/
@Repository
@RequiredArgsConstructor
public class ItemRepository {
private final SqlSession sqlSession;
public List<Item> selectItems(ItemCondition condition) {
return sqlSession.selectList("selectItems", condition);
}
}
ItemService.java
import java.util.List;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import serendip.spring.sample.mybatis.model.Item;
import serendip.spring.sample.mybatis.model.ItemCondition;
import serendip.spring.sample.mybatis.repository.ItemRepository;
/**
*Produktsuche Service.
*/
@Service
@RequiredArgsConstructor
public class ItemService {
private final ItemRepository repository;
public List<Item> selectItems(ItemCondition condition) {
return repository.selectItems(condition);
}
}
Artikelbedingung der Suchbedingung. Die zuvor definierte Aufzählung wird als Bedingung angegeben.
ItemCondition.java
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
/**
*Bedingungen für die Produktsuche.
*/
@Builder
@ToString
@Getter
public class ItemCondition {
private int id;
private ItemPublish status;
private TrueOrFalse display;
}
Element, das einen Datensatz des Suchergebnisses darstellt. Die Werte für Spaltenstatus und Anzeige werden von der definierten Aufzählung behandelt.
Item.java
import lombok.Getter;
import lombok.Setter;
/**
*Produkttabelle(Item)1 Aufzeichnung von.
*/
@Getter @Setter
public class Item {
private Integer id;
private String name;
private ItemPublish status;
private TrueOrFalse display;
}
Die diesmal auszuführende SQL lautet wie folgt.
sql-mappings.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="serendip.spring.sample.mybatis.repository.MemberRepository">
<select id="selectItems"
parameterType="serendip.spring.sample.mybatis.model.ItemCondition"
resultType="serendip.spring.sample.mybatis.model.Item">
SELECT
id,
name,
status,
display
FROM
item
</select>
</mapper>
Jetzt ist die Implementierungsklasse fertig. Wenn Mybatis so ausgeführt wird, wie es ist, wird es automatisch in enum konvertiert. Es wird jedoch eine Laufzeitausnahme ausgelöst, da die standardmäßig auszuführende Methode [^ 5] nicht abgerufen werden kann.
Daher verwendet Mybatis TypeHandler, der die Typkonvertierung für eine bestimmte Aufzählung durchführt.
Mit TypeHandler konvertiert Mybatis zwischen der Java-Klasse und der in der SQLMapping-Definition enthaltenen Datenbank.
Der implementierte TypeHandler ist im Paket org.apache.ibatis.type von Mybatis enthalten. Hier definieren wir die Konvertierung für Java-Typen und den TypeHandler für die in Datenbankspalten verwendeten Typen. Beispielsweise werden auch die Big Decimal-Typkonvertierung und die Datenbank-BLOB-Typkonvertierung von Java bereitgestellt, die die in der Pretared-Anweisung von JDBC enthaltenen Funktionen ausführen.
TypeHandler von Mybatis wird von BaseTypeHandler
ItemPublishTypeHandler.java
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import serendip.spring.sample.mybatis.model.ItemPublish;
/**
*Geben Sie die Konvertierungsklasse für die Aufzählung des Status der Produktveröffentlichung ein.
*/
public class ItemPublishTypeHandler extends BaseTypeHandler<ItemPublish> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, ItemPublish parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.getValue());
}
@Override
public ItemPublish getNullableResult(ResultSet rs, String columnName) throws SQLException {
return ItemPublish.getDisplayStatus(rs.getString(columnName));
}
@Override
public ItemPublish getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return ItemPublish.getDisplayStatus(rs.getString(columnIndex));
}
@Override
public ItemPublish getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return ItemPublish.getDisplayStatus(cs.getString(columnIndex));
}
}
TrueOrFalseTypeHandler.java
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import serendip.spring.sample.mybatis.model.TrueOrFalse;
/**
*Eine Typkonvertierungsklasse für Enum, die Flags verarbeitet.
*/
public class TrueOrFalseTypeHandler extends BaseTypeHandler<TrueOrFalse> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, TrueOrFalse parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter.getValue());
}
@Override
public TrueOrFalse getNullableResult(ResultSet rs, String columnName) throws SQLException {
return TrueOrFalse.getTrueOrFalse(rs.getString(columnName));
}
@Override
public TrueOrFalse getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return TrueOrFalse.getTrueOrFalse(rs.getString(columnIndex));
}
@Override
public TrueOrFalse getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return TrueOrFalse.getTrueOrFalse(cs.getString(columnIndex));
}
}
Beschreiben des erstellten TypeHandlers in der Mybatis-Konfigurationsdatei. Beschreiben Sie den TypeHandler, der vom Element
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeHandlers>
<typeHandler handler="serendip.spring.sample.mybatis.typehandler.ItemPublishTypeHandler"/>
<typeHandler handler="serendip.spring.sample.mybatis.typehandler.TrueOrFalseTypeHandler"/>
</typeHandlers>
...
</configuration>
Zusätzlich zu den Suchergebnissen aus der Datenbank kann TypeHandler auf Argumente (Parameter) angewendet werden.
Die Suchbedingung verwendet TrueOrFalse von ItemCondition, wie oben erwähnt. Für die präziseste Verwendung gibt es eine Möglichkeit, den Wert mit getValue () von enum abzurufen.
sql-mappings.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="serendip.spring.sample.mybatis.repository.MemberRepository">
<select id="selectItems"
parameterType="serendip.spring.sample.mybatis.model.ItemCondition"
resultType="serendip.spring.sample.mybatis.model.Item">
SELECT
id,
name,
status,
display
FROM
item
<where>
<if test="display.getValue() != ''">
display = #{display.value}
</if>
</where>
</select>
</mapper>
Diese Methode ist jedoch etwas unvernünftig, da sie den beschriebenen Inhalt nur mit enum mit Zeichenfolgen in dynamischem SQL vergleicht. Mybatis kann jedoch dynamische SQL-bedingte Anweisungen in OGNL schreiben.
Lass es uns benutzen.
Um in OGNL auf enum zu verweisen, verwenden Sie den vollständigen Klassennamen @ enumerator von @ enum wie folgt.
sql-mappings.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="serendip.spring.sample.mybatis.repository.MemberRepository">
<select id="selectItems"
parameterType="serendip.spring.sample.mybatis.model.ItemCondition"
resultType="serendip.spring.sample.mybatis.model.Item">
SELECT
id,
name,
status,
display
FROM
item
<where>
<if test="display != @serendip.spring.sample.mybatis.model.TrueOrFalse@NONE">
display = #{display.value}
</if>
</where>
</select>
</mapper>
Jetzt können Sie enum auf die bedingte Verzweigung von dynamischem SQL anwenden.
Führen Sie den diesmal eingeführten Inhalt von RestController of Spring aus und erstellen Sie ihn so, dass eine Antwort im JSON-Format zurückgegeben wird.
import java.util.List;
import java.util.Optional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import serendip.spring.sample.mybatis.model.Item;
import serendip.spring.sample.mybatis.model.ItemCondition;
import serendip.spring.sample.mybatis.model.ItemPublish;
import serendip.spring.sample.mybatis.model.TrueOrFalse;
import serendip.spring.sample.mybatis.service.ItemService;
/**
*Produktsuche RestController.
*/
@RestController
@RequestMapping("/items")
@RequiredArgsConstructor
public class ItemController {
private final ItemService service;
@GetMapping("")
public List<Item> searchItems(@RequestParam Optional<String> publish, @RequestParam Optional<String> display) {
ItemCondition condition = ItemCondition.builder()
.status(ItemPublish.getDisplayStatus(publish.orElse("")))
.display(TrueOrFalse.getTrueOrFalse(display.orElse("")))
.build();
return service.selectItems(condition);
}
}
Unter der Annahme, dass die Suchbedingung nicht festgelegt ist, ist der Parameter, wenn er undefiniert ist, der Wert, wenn er in jedem Aufzählungswert undefiniert ist.
http://127.0.0.1:8080/items
[
{
"id": 1,
"name": "Holzstuhl",
"status": "NONE",
"display": "TRUE"
},
{
"id": 2,
"name": "Glas tisch",
"status": "PUBLISH",
"display": "TRUE"
},
{
"id": 3,
"name": "Holztisch",
"status": "MEMBER_ONLY",
"display": "FALSE"
}
]
http://127.0.0.1:8080/items?display=0
[
{
"id": 3,
"name": "Holztisch",
"status": "MEMBER_ONLY",
"display": "FALSE"
}
]
http://127.0.0.1:8080/items?display=1
[
{
"id": 1,
"name": "Holzstuhl",
"status": "NONE",
"display": "TRUE"
},
{
"id": 2,
"name": "Glas tisch",
"status": "PUBLISH",
"display": "TRUE"
}
]
Für diesen Parameterwert wird der Datenbankwert so wie er ist als Bedingungswert verwendet, es können jedoch auch andere Werte im Controller verwendet werden. Wenn Sie den JSON-Antwortwert weiter konvertieren möchten, implementieren Sie die JsonSerialize-Schnittstelle von jackson in enum und sie wird automatisch konvertiert.
Wir hoffen, dass Sie die automatische Typkonvertierung und Wertekonvertierung verwenden können, um eine robustere und wartbarere Anwendung (・ ω ・) zu erstellen.
[^ 1]: Der Inhalt enthält auch eine "Entwicklungssite oder einen Herstellerdialekt", der durch das "Flag" und den "Klassifizierungswert" gekennzeichnet ist. In diesem Artikel ist "Flag" eine Spalte mit nur zwei Werten, dh eine Spalte, die nur wahr / falsch des sogenannten Booleschen Werts anzeigt, und "Teilungswert" ist eine Spalte mit einem festen Bereich möglicher Werte für andere Zwecke als den Booleschen Wert. [^ 2]: Es gibt beispielsweise Fälle, in denen das Lösch- und das Aktualisierungsflag, die selbst ab 2018 nicht mehr so vorzuziehen sind, unabhängig davon existieren, ob das System alt oder neu ist. 0: gültiger Datensatz, 1: gelöscht usw. [^ 3]: Der Spaltenname wird absichtlich schlampig gemacht, was aus dem Namen, der eher ein Altsystem ist, schwer zu erraten ist. Was sind Status und Anzeige! ?? Wird es sein? [^ 4]: Dieses Mal gebe ich immer einen Wert zurück, aber wenn ein unmöglicher Wert angegeben wird, kann dies eine Anwendungsausnahme auslösen. [^ 5]: Die Methode java.lang.Enum.valueOf wird ausgeführt.
Recommended Posts