blog

SpringCloudベースの列挙値の国際化処理プラクティス

永続層のストレージの最適化ルールに由来し、int型はvarchar型よりもはるかに効率的であり、プラクティスのこのセットはまた、非常に非常にみんなに受け入れられています。 状態値のマッピングの定数定義...

Jun 17, 2020 · 6 min. read
シェア

コンテキスト

SpringCloudフレームワークを選択してマイクロサービスを構築し、ビジネスバックエンドアプリケーションを行う場合、多くのビジネスステート値の定義が必要になります:

  • 永続化レイヤはint型の値を格納します。
  • バックエンドシステムは、int型の値をもう少し読みやすい定数にレイヤーマッピングします。
  • フロントエンドは、これらの関係をマップするための定数セットも定義します。
  • フロントエンドがバックエンドシステムのインターフェイスを呼び出すとき、定数で定義された int 型がサブミッションに使用されます。

永続層ストレージの最適化ルールに由来して、int型はvarchar型よりもはるかに効率的であり、この一連のプラクティスは非常によく受け入れられています。

状態値のマッピングのための定数の定義には、フロントエンドとバックエンドの両方のパートが関与し、通信コストがかかるという一面もあり、さらに、状態値に変更があった場合、両方のグループで同時に修正する必要があるという点です。

希望ゴール

永続層では、問題の可読性のビジネスの状態の主な考慮事項の前提の下でストレージ状態の値のint型と複数の変更の問題を確保するために、問題の可読性の問題の一部は、定数のフロントとバックエンドスタッフの定義を介して解決することができますが、インターフェイスのデバッグは、まだ問題の可読性の一部であるint型の直接使用は、まだ存在し、複数の変更は、問題の解決に焦点を当てる必要があります。

このポストの推奨プログラム

  • 永続層ストレージは元のint値を使用しません。
  • バックエンドシステムはビジネス状態を定義するためにenumを使用し、異なるビジネス状態のセットは複数のenumによって実現することができ、enumは国際化をサポートします。
  • 列挙型の国際化テキストのフロントエンド表示
  • フロントエンドがバックエンドのシステムインターフェイスを呼び出すとき、enum国際化テキストコンテンツを使用して送信します。
  • バックエンドはenum国際化のテキストコンテンツを受け取り、int値に変換し、データベースに保存します。

プログラムの利点

  • 永続化レイヤーの本来の設計は、効率の問題には影響されません。
  • ビジネスステートの定義とマッピングはすべてバックエンドシステムと一体化されているため、その後ステートの値が変更された場合でも、それに応じてバックエンドを修正するだけで済みます。
  • フロントエンドによって表示され、インターフェイスによって送信されるコンテンツは、より読みやすいテキストであり、国際化をサポートしています。

プログラムのデメリット

  • バックエンドシステムが状態の値を保存したり読み込んだりする際には、enum
  • 通信によって送信されるコンテンツメッセージは、元のint型よりも少し大きくなります。

プログラムの実践

実践の原則

この実践的なプログラムは主に3つのパートで構成されています:

  1. Enumクラスは、JSONのシリアライズとデシリアライズにJacksonを使用しています。
  2. Enum
  3. Enum

列挙型カスタムのシリアライズとデシリアライズ

@JsonDeserialize(using = DescEnumDeserializer.class)
@JsonSerialize(using = DescEnumSerializer.class)
public interface I18NEnum {
 /**
 * 列挙型の説明を取得する
 *
 * @return
 */
 String getDesc();
}
/**
 * 
 */
public class DescEnumSerializer extends JsonSerializer<I18NEnum> {
 @Override
 public void serialize(I18NEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
 //  +列挙値名スプライシングプロファイルキー、すべて大文字の処理
 String key = value.getClass().getSimpleName() + "." + StringUtils.upperCase(value.toString());
 // I18NUtil国際化のための処理ツール
 String data = I18NUtil.get(key, value.getDesc());
 gen.writeString(data);
 }
}

カスタムデシリアライズの実装:

/**
 * 
 */
public class DescEnumDeserializer extends JsonDeserializer<I18NEnum> {
 @Override
 public I18NEnum deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
 JsonNode node = p.getCodec().readTree(p);
 Class enumCls = BeanUtils.findPropertyType(p.currentName(), p.getCurrentValue().getClass());
 List enumFields = EnumUtils.getEnumList(enumCls);
 String keyPrefix = enumCls.getSimpleName() + ".";
 for (Object enumField : enumFields) {
 I18NEnum i18NEnum = (I18NEnum) enumField;
 // I18NUtil国際化のためのツールを処理する
 String data = I18NUtil.get(keyPrefix + StringUtils.upperCase(i18NEnum.toString()), i18NEnum.getDesc());
 if (node.asText().equals(data)) {
 return i18NEnum;
 }
 }
 throw new I18NEnumException("enum:不明な列挙型");
 }
}

専用の例外をカスタマイズして、より高く見えるようにします:

/**
 * 
 */
public class I18NEnumException extends RuntimeException {
 public I18NEnumException(String message) {
 super(message);
 }
}
国際化処理ツールカテゴリー
/**
 * 
 */
@Component
public class I18NUtil {
 private static MessageSource messageSource;
 public I18NUtil(MessageSource messageSource) {
 I18NUtil.messageSource = messageSource;
 }
 public static String get(String key) {
 return messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
 }
 public static String get(String key, Object arg) {
 return messageSource.getMessage(key, new Object[]{arg}, LocaleContextHolder.getLocale());
 }
}
列挙型の定義例

列挙型の定義の例として、2つの列挙型値SUCCESSとFAILがあり、それぞれint値が1と2でデータベースに格納されています:

public enum OperateEnum implements I18NEnum {
	/**
	 * 個人的な日常消費
	 */
	SUCCESS(1, "SUCCESS"),
	/**
	 *  
	 */
	FAIL(2,"FAIL");
	private int index;
	private String desc;
	OperateEnum(int index, String desc) {
		this.index = index;
		this.desc = desc;
	}
	@Override
	public String getDesc() {
		return desc;
	}
	public int getIndex() {
		return index;
	}
}

設定ファイルの書き込み:

# messages.properties 
#  
OperateEnum.SUCCESS=success
OperateEnum.FAIL=fail
# messages_zh.properties 
#  
OperateEnum.SUCCESS=成功した操作
OperateEnum.FAIL=操作の失敗

プログラム申込

SpringCloud環境で、国際化された言語の処理を追加し、リクエストヘッダのlangに国際言語識別子を入れます:

/**
 * 
 */
public class I18NLocalResolver implements LocaleResolver {
 @Override
 public Locale resolveLocale(HttpServletRequest request) {
 String lang = request.getHeader("lang");
 //jvmのデフォルトを取得するlocale
 Locale locale = Locale.getDefault();
 if (lang != null) {
 locale = new Locale(lang);
 }
 return locale;
 }
 @Override
 public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
 }
}

カスタム列挙型の直列化メソッドのトリガー

インターフェイスでは、enumクラスを返すだけでよく、@ResponseBodyの処理で、シリアライズメソッドのenumの国際化をトリガーできます:

@ApiOperation(value = "列挙値の国際化の例")
@ApiImplicitParams({
		@ApiImplicitParam(name = "uid", value = "オペレータID", paramType = "header", dataType = "Long")})
@RequestMapping(value = "/test/enums", method = RequestMethod.GET)
public Result get(
		@RequestHeader(value = "lang") String lang) {
	return Result.success(EnumUtils.getEnumList(OperateEnum.class));
}

カスタム列挙型のデシリアライズ・メソッドのトリガー

MappingJackson2HttpMessageConverter コンバータは、デフォルトでは @RequestBody の内容をデシリアライズします。 enum の国際化された値がクライアントに渡され、クライアントから送信された enum の国際化された内容を正しく処理する必要がある場合、最も簡単な方法は、@RequestBody オブジェクトで enum を定義することです。で enum を定義することです。これにより enum のカスタムデシリアライズメソッドが自動的に起動し、 望みの結果が得られます。

enumオブジェクトが@RequestParamで変更されたパラメータで定義されている場合、リクエストのStringからenumへの変換は、org.springframework.core.convert.support.StringToEnumConverterFactoryというインターフェイスを実装したクラスによって実現されます。このクラスは列挙型の列挙値のデシリアライズをトリガーせずに Enum.valueOf(Class, String) を呼び出すことでこの機能を実装しています。したがって、列挙値と同じリテラル値のみを扱うことができます。 列挙値の国際化後、リテラル値と同じでない場合があり、@RequestParam を使用して直接変換するとエラーが報告されます。

RequestParamを列挙型の値に対するデシリアライズ操作のトリガーにするには、ここでは省略しますが、springmvcのパラメータコンバータを書き換えてみてください。

短い

処理の国際化のenum列挙値は、非常に興味深い改善であり、両方の可読性の問題を解決するかもしれませんが、また、ビジネス定義の結束を向上させるために、このプログラムのアプリケーションは、コーディングの習慣のフロントとバックエンドに依存し、プロジェクトの初期段階にある場合は、フロントとバックエンドの子供の靴は、このプログラムを試すことができることを確認するために通信するために、私はあなたの助けになることを願っています。

()

Read next

分数を小数に変換する。

小数の無限ループが発生するかどうかを判断するには、ループ部分を見つける必要があります。\n\n最終結果は0です。\n発生した四則演算を追跡するために、ハッシュテーブルが必要で、割り算は、全体の割り算が行われるか、循環ナックルが発生するかのどちらかになるまで、何度も何度も行うことができます。\n\nコードは以下の通り:\nクラス Solu

Jun 17, 2020 · 2 min read