2012-03-23 11 views
12

हम जेपीए 2 पर आधारित जावा वेब परियोजना पर काम कर रहे हैं के लिए अद्वितीय उल्लंघन अपवाद प्रचार, हाइबरनेट, स्प्रिंग 3 और JSF 2 बिलाव 7 में चल रहे हम डाटाबेस के रूप में Oracle 11g उपयोग कर रहे हैं।सर्वश्रेष्ठ अभ्यास यूआई

हम वर्तमान दृष्टिकोण पर एक बहस पकड़े हुए हैं यूआई के लिए उपयोगकर्ता के अनुकूल संदेश के रूप में डेटाबेस बाधा के उल्लंघन को भरने के लिए। कम या ज्यादा हम दो तरीकों से देखते हैं, दोनों वास्तव में संतोषजनक नहीं हैं। क्या कोई कुछ सलाह दे सकता है?

दृष्टिकोण 1 - प्रोग्राम के रूप में सत्यापित करें और फेंक विशिष्ट अपवाद

CountryService.java में प्रत्येक अद्वितीय बाधा सत्यापित किया जाएगा, और एक इसी अपवाद फेंक दिया है। अपवादों को एक बैकिंग बीन में व्यक्तिगत रूप से संभाला जाता है।

लाभ: समझते हैं और बनाए रखने के लिए आसान। विशिष्ट उपयोगकर्ता संदेश संभव है।

नुकसान: अच्छे संदेश रखने के लिए बहुत सारे कोड। असल में सभी डीबी प्रतिबंध आवेदन में फिर से लिखे गए हैं। बहुत सारे प्रश्न - अनावश्यक डीबी लोड।

@Service("countryService") 
public class CountryServiceImpl implements CountryService { 

    @Inject 
    private CountryRepository countryRepository; 

    @Override 
    public Country saveCountry(Country country) throws NameUniqueViolationException, IsoCodeUniqueViolationException, UrlUniqueViolationException { 
     if (!isUniqueNameInDatabase(country)) { 
      throw new NameUniqueViolationException(); 
     } 
     if (!isUniqueUrl(country)) { 
      throw new UrlUniqueViolationException(); 
     } 
     if (!isUniqueIsoCodeInDatabase(country)) { 
      throw new IsoCodeUniqueViolationException(); 
     } 
     return countryRepository.save(country); 
    } 
} 

देखें के समर्थन बीन में आप अपवाद संभाल:

@Component 
@Scope(value = "view") 
public class CountryBean { 

    private Country country; 

    @Inject 
    private CountryService countryService; 

    public void saveCountryAction() { 
     try { 
      countryService.saveCountry(country); 
     } catch (NameUniqueViolationException e) { 
      FacesContext.getCurrentInstance().addMessage("name", new FacesMessage("A country with the same name already exists.")); 
     } catch (IsoCodeUniqueViolationException e) { 
      FacesContext.getCurrentInstance().addMessage("isocode", new FacesMessage("A country with the same isocode already exists.")); 
     } catch (UrlUniqueViolationException e) { 
      FacesContext.getCurrentInstance().addMessage("url", new FacesMessage("A country with the same url already exists.")); 
     } catch (DataIntegrityViolationException e) { 
      // update: in case of concurrent modfications. should not happen often 
      FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("The country could not be saved.")); 
     } 
    } 
} 

दृष्टिकोण 2 - डेटाबेस बाधा उल्लंघन

लाभ का पता लगाने के चलो: नहीं बॉयलर प्लेट कोड। डीबी के लिए कोई अनावश्यक प्रश्न नहीं। डेटा बाधा तर्क का कोई डुप्लिकेशन नहीं।

नुकसान: निर्भरता डीबी में नामों में रोके, तो स्कीमा की पीढ़ी के माध्यम से संभव नहीं हाइबरनेट। इनपुट घटकों को संदेश बाध्य करने के लिए तंत्र की आवश्यकता होती है (उदा। हाइलाइटिंग के लिए)।

public class DataIntegrityViolationExceptionsAdvice { 
    public void afterThrowing(DataIntegrityViolationException ex) throws DataIntegrityViolationException { 

     // extract the affected database constraint name: 
     String constraintName = null; 
     if ((ex.getCause() != null) && (ex.getCause() instanceof ConstraintViolationException)) { 
      constraintName = ((ConstraintViolationException) ex.getCause()).getConstraintName(); 
     } 

     // create a detailed message from the constraint name if possible 
     String message = ConstraintMsgKeyMappingResolver.map(constraintName); 
     if (message != null) { 
      throw new DetailedConstraintViolationException(message, ex); 
     } 
     throw ex; 
    } 
} 
+0

आप अभी भी दृष्टिकोण 1 में बाधा उल्लंघन का पता लगाने के लिए डेटाबेस पर भरोसा कर रहे हैं, यदि उपयोगकर्ता अद्वितीय जांच के बाद डुप्लिकेट देश बचाता है लेकिन दूसरे उपयोगकर्ता की बचत से पहले। – ken

+0

हम यहां समवर्ती मुद्दे से अवगत हैं। हमारे उपयोग के मामलों के लिए यह अनिवार्य नहीं है।यह पर्याप्त है, अगर 90% मामलों में संदेश विशिष्ट है। यदि असाधारण मामलों में, डीबी द्वारा एक अधिक सामान्य संदेश ट्रिगर किया जाता है इससे कोई फर्क नहीं पड़ता। – fischermatte

+0

मैंने दृष्टिकोण 1 – fischermatte

उत्तर

9

दृष्टिकोण 1 एक समवर्ती परिदृश्य में काम नहीं करेगा! - हमेशा एक परिवर्तन होता है कि किसी और ने चेक किए जाने के बाद एक नया डेटाबेस रिकॉर्ड डाला लेकिन आपके डेटाबेस रिकॉर्ड को जोड़ने से पहले। (सिवाय इसके कि आप अलगाव स्तर serializable का उपयोग करें, लेकिन यह बेहद असंभव है)

तो आपको डीबी बाधा उल्लंघन उल्लंघन को संभालना होगा। लेकिन मैं डेटाबेस अपवाद को पकड़ने की अनुशंसा करता हूं जो अद्वितीय उल्लंघनों को इंगित करता है और आपके दृष्टिकोण के अनुसार एक और अर्थ भरा हुआ है।

+0

अपडेट किया जैसा कि मैंने केन को लिखा था, समवर्ती मुद्दा कोई फर्क नहीं पड़ता। उन असाधारण मामलों में एक और सामान्य संदेश (डीबी द्वारा ट्रिगर किया गया उल्लंघन दिखाया जाएगा)। अद्यतन दृष्टिकोण 1. – fischermatte

+0

वैसे भी, यह मेरे सुझाए गए दृष्टिकोण को नहीं बदलेगा। – Ralph

+0

मुझे इसके बारे में क्या पसंद नहीं है, यह है कि आम तौर पर विकास हाइबरनेट के दौरान बाधाओं का नाम उत्पन्न होगा। दृष्टिकोण 2 के साथ हमें अतिरिक्त स्क्रिप्ट के माध्यम से नामों को अलग-अलग बनाए रखने की आवश्यकता है। – fischermatte

8

यह एक विकल्प भी हो सकता है, और यह कम महंगा हो सकता है क्योंकि आप केवल विस्तृत जानकारी के लिए जांच करते हैं अपवाद आप एकमुश्त नहीं बचा सकता है, तो:

try { 
    return countryRepository.save(country); 
} 
catch (DataIntegrityViolationException ex) { 
    if (!isUniqueNameInDatabase(country)) { 
     throw new NameUniqueViolationException(); 
    } 
    if (!isUniqueUrl(country)) { 
     throw new UrlUniqueViolationException(); 
    } 
    if (!isUniqueIsoCodeInDatabase(country)) { 
     throw new IsoCodeUniqueViolationException(); 
    } 
    throw ex; 
} 
+2

Thx है, दृष्टिकोण 1 से निश्चित रूप से बेहतर है! मुझे लगता है कि केवल दोष है, कि आपको 'countryRepository.save (देश)' कॉल करने के बाद मैन्युअल रूप से फ़्लश करने की आवश्यकता है। – fischermatte

0

ExceptionInfoHandler में बॉयलरप्लेट मैं DataIntegrityViolationException इलाज से बचने के लिए मूल कारण संदेश में डीबी की कमी घटनाओं खोजने और मानचित्र के माध्यम से i18n संदेश में परिवर्तित करने के लिए। यहां कोड देखें: https://stackoverflow.com/a/42422568/548473