検証グループ †
- ExamBean2.java
package com.mycompany.beanvalidatorexam;
import javax.validation.GroupSequence;
import javax.validation.groups.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@ToString
public class ExamBean2 implements GroupValidatable {
@GroupSequence({ Default.class, grpCreditCard.class })
interface payByCreditCard{};
@GroupSequence({ Default.class, grpBankTransfer.class })
interface payByBankTransfer{};
interface grpCreditCard{};
interface grpBankTransfer{};
@NotEmpty // 暗黙に javax.validation.groups.Default が設定されている
private String name;
@NotEmpty // 暗黙に javax.validation.groups.Default が設定されている
private String addr;
@NotEmpty // 暗黙に javax.validation.groups.Default が設定されている
private String paymentMethod;
@NotEmpty(message = "なんか入れろ", groups = {grpCreditCard.class}) // ← message は無視される
private String cardType;
@NotEmpty(groups = {grpCreditCard.class})
@CreditCard(groups = {grpCreditCard.class})
private String cardNo;
@NotEmpty(groups = {grpCreditCard.class})
private String cardAvail;
@NotEmpty(groups = {grpCreditCard.class})
private String cardCode;
@NotEmpty(groups = {grpBankTransfer.class})
private String bankNo;
@NotEmpty(groups = {grpBankTransfer.class})
private String bankName;
@NotEmpty(groups = {grpBankTransfer.class})
private String bankNominal;
@Override
public Class[] validateGroups() {
switch(paymentMethod) {
case "creditCard":
return new Class[]{payByCreditCard.class};
default:
return new Class[]{payByBankTransfer.class};
}
}
}
- BeanValidator? のアノテーションには、検証 group を指定することができる
- 検証時の第二引数に group のリストを指定すると、そこだけ検証する
Set<ConstraintViolation<ExamBean2>> violations = validator.validate(bean, bean.validateGroups());
- Bean の状態によって、検証シナリオを返す GroupValidatable? Interface を作ろう
package com.mycompany.beanvalidatorexam;
public interface GroupValidatable {
Class[] validateGroups();
}
JAX-RSから使ってみる †
index2.html †
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Start Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/tooltipster.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="js/jquery.tooltipster.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#frmValidate').on('submit', function() {
// form -> [{name:xxx, value:yyy},{name:ppp, value:qqq},...]
var params = $(this).serializeArray();
// -> {xxx:yyy, ppp:qqq, ...}
var args = new Object();
for (var cnt = 0; cnt < params.length; cnt++) {
args[ params[cnt].name ] = params[cnt].value;
}
// turn warings off
$(this).find('input').each(function(index, element) {
$(element).css({background: 'white'});
// tooltipstar throw exception if ui-component is not initialized as tooltipstar component.
try {
$(element).tooltipster('destroy');
} catch (e) {
}
});
$.ajax({
url: "webresources/exam/pay",
type: "POST",
data: JSON.stringify(args),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
if (data.success) {
alert('Your order is accepted.');
return;
}
var violations = data.errors.entry;
for (var cnt = 0; cnt < violations.length; cnt++) {
var violation = violations[cnt];
var $component = $('#' + violation.key);
// turn warings on
if ($component) {
$component.css({background: 'pink'});
$component.tooltipster({postion: 'top', content: violation.value}).tooltipster('show');
}
}
},
error: function(data, status) {
console.log(data);
console.log(status);
alert('Sorry, your order is abended.');
}
});
// reject from submit, we want to use ajax.
return false;
});
});
</script>
</head>
<body>
<h1>Hello Complex Bean Validator!</h1>
<form id="frmValidate">
<table>
<tbody>
<tr> <td>Name</td> <td> <input id="name" name="name" type="text" value="鬼太郎"/> </td> </tr>
<tr> <td>Address</td> <td> <input id="addr" name="addr" type="text" value="鳥取県境港市"/> </td> </tr>
<tr>
<td valign="top">Payment<br/>Method</td>
<td>
<fieldset style="width:240px">
<legend><label><input name="paymentMethod" value="creditCard" type="radio" checked="checked"/>Credit Card</label></legend>
<select id="cardType" name="cardType">
<option>AMEX</option>
<option>VISA</option>
<option>JCB</option>
</select>
<table>
<tbody>
<tr><td>No</td> <td><input id="cardNo" name="cardNo" type="text" value=""/></td>
<tr><td>Avail</td> <td><input id="cardAvail" name="cardAvail" type="month" value=""/></td>
<tr><td>Code</td> <td><input id="cardCode" name="cardCode" type="text" value=""/></td>
</tbody>
</table>
</fieldset>
<fieldset style="width:240px">
<legend><label><label><input name="paymentMethod" value="bankTransfer" type="radio"/>Bank Transfer</label></legend>
<select id="bankName" name="bankName">
<option>CITY</option>
<option>MIZUHO</option>
<option>JP-BANK</option>
</select>
<table>
<tbody>
<tr><td>No</td> <td><input id="bankNo" name="bankNo" type="text" value=""/></td>
<tr><td>Nominal</td> <td><input id="bankNominal" name="bankNominal" type="text" value=""/></td>
</tbody>
</table>
</fieldset>
</td>
</tr>
<tr> <td colspan="2" align="right">
<button id="btnPay">Pay</button>
</td></tr>
</tbody>
</table>
</form>
</body>
</html>
BVExamResource?.java †
package com.mycompany.beanvalidatorexam;
import java.util.Set;
import javax.enterprise.context.RequestScoped;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("exam")
@RequestScoped
public class BVExamResource {
@Context
private UriInfo context;
public BVExamResource() {
}
@POST
@Path("order")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public ResponseBean orderStock(ExamBean bean) {
ResponseBean<ExamBean> res = new ResponseBean();
// We can't @Inject Validator on Glassfish 4.0, 4.0.1 may be fix it.
final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<ExamBean>> violations = validator.validate(bean);
System.out.println(violations.toString());
if (!violations.isEmpty()) {
// There are some validation errors
res.setSuccess(false);
res.setValidationError(violations);
return res;
}
res.setSuccess(true);
return res;
}
@POST
@Path("pay")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public ResponseBean payment(ExamBean2 bean) {
ResponseBean<ExamBean2> res = new ResponseBean();
// We can't @Inject Validator on Glassfish 4.0, 4.0.1 may be fix it.
final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<ExamBean2>> violations = validator.validate(bean, bean.validateGroups());
System.out.println(violations.toString());
if (!violations.isEmpty()) {
// There are some validation errors
res.setSuccess(false);
res.setValidationError(violations);
return res;
}
res.setSuccess(true);
return res;
}
}
実行結果 †
- クレジットカード払いなので、振替口座が未記入でも OK
- 振替払いなので、クレジットカードが記入されていても BAD
- Default でエラーがあると、Group の検証がされない
Java#Glassfish