স্প্রিং এমভিসি: জিইটি @ রিকোয়েস্টপ্রাম হিসাবে কমপ্লেক্স অবজেক্ট


191

ধরুন আমার কাছে এমন একটি পৃষ্ঠা রয়েছে যা টেবিলের উপরে অবজেক্টগুলি তালিকাভুক্ত করে এবং টেবিলটি ফিল্টার করার জন্য আমার একটি ফর্ম রাখা দরকার। ফিল্টারটি আজাক্স জিইটি হিসাবে একটি ইউআরএলকে প্রেরণ করা হয়: http://foo.com / সিস্টেমে / কন্ট্রোলার / অ্যাকশন? পৃষ্ঠা=1&prop1=x&prop2=y&prop3=z

এবং আমার কন্ট্রোলারে প্রচুর পরামিতি রাখার পরিবর্তে:

@RequestMapping(value = "/action")
public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    @RequestParam(value = "prop1", required = false) String prop1,
    @RequestParam(value = "prop2", required = false) String prop2,
    @RequestParam(value = "prop3", required = false) String prop3) { ... }

এবং ধরুন আমার কাছে মাইবজেক্টটি রয়েছে:

public class MyObject {
    private String prop1;
    private String prop2;
    private String prop3;

    //Getters and setters
    ...
}

আমি এরকম কিছু করতে চাই:

@RequestMapping(value = "/action")
public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    @RequestParam(value = "myObject", required = false) MyObject myObject,) { ... }

এটা কি সম্ভব? আমি এটা কিভাবে করবো?


1
'@RequestMapping' এর সাথে মিলিত '@ মডেলএট্রিবিউট' ব্যবহার করার চেষ্টা করুন, যেখানে মাইবজেক্ট আপনার মডেল হবে।
মিশাল

@ মিমাল +1। এটি কীভাবে করবেন তা দেখানোর জন্য এখানে কয়েকটি টিউটোরিয়াল দেওয়া হয়েছে: স্প্রিং 3 এমভিসি: স্প্রিংয়ে হ্যান্ডলিং ফর্ম 3.0 এমভিসি , কী এবং কীভাবে ব্যবহার করতে হয়@ModelAttribute , স্প্রিং এমভিসি ফর্ম হ্যান্ডলিংয়ের উদাহরণ । কেবল " স্প্রিং এমভিসি ফর্ম হ্যান্ডলিং " গুগল করুন এবং আপনি এক টন টিউটোরিয়াল / উদাহরণ পাবেন। কিন্তু ফর্ম হ্যান্ডলিং আধুনিক উপায় ব্যবহার নিশ্চিত করা, অর্থাত্ স্প্রিং v2.5 + +
informatik01

উত্তর:


247

আপনি একেবারে এটি করতে পারেন, কেবল @RequestParamটীকাটি সরিয়ে ফেলুন , স্প্রিং আপনার ক্লাসের উদাহরণের সাথে আপনার অনুরোধের প্যারামিটারগুলি পরিষ্কারভাবে আবদ্ধ করবে:

public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    MyObject myObject)

8
বিজু, আপনি কীভাবে এটিকে ডাকবেন তার একটি উদাহরণ দিতে পারেন? আমি রেস্ট এপিআই তে একটি বেসিক http জিইটি কল করছি এবং এর কোনও অভিনব রূপ নেই।
বিসচন্দ্রমোহন

33
নোট করুন যে বসন্তটি ডিফল্টরূপে মাইওবজেক্টটিকে স্বয়ংক্রিয়ভাবে বাঁধাই করার জন্য গ্রাহকরা / সেটটারগুলির প্রয়োজন হয়। যাইহোক এটি মাইবজেক্টকে আবদ্ধ করবে না।
ওরফে_

20
আপনি কীভাবে ক্ষেত্রগুলি মাইওবজেক্টে /চ্ছিক / অ-?চ্ছিক সেট করতে পারেন?
এটির

6
@ বিজু, ডিফল্ট মান নিয়ন্ত্রণের কোনও উপায় কি তার জন্য প্রয়োজনীয় MyObject, একইভাবে আমরা @RequestParam এর সাথে করতে পারি?
আলেক্সি

7
@ বিজুকুঞ্জুমেন কীভাবে আমি MyObjectসাপ ক্ষেত্রে ক্যোয়ারী প্যারামিটারগুলি গ্রহণ করতে আপডেট করতে পারি এবং এর একটি উটের কেস সদস্যকে এটি ম্যাপ করতে পারি MyObject। উদাহরণস্বরূপ, এর সদস্যের ?book_id=4সাথে ম্যাপ করা উচিত ? bookIdMyObject
বিবেক বর্ধন

55

আমি আমার কাছ থেকে কিছু সংক্ষিপ্ত উদাহরণ যুক্ত করব।

ডিটিও ক্লাস:

public class SearchDTO {
    private Long id[];

    public Long[] getId() {
        return id;
    }

    public void setId(Long[] id) {
        this.id = id;
    }
    // reflection toString from apache commons
    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

নিয়ামক শ্রেণীর ভিতরে ম্যাপিংয়ের অনুরোধ করুন:

@RequestMapping(value="/handle", method=RequestMethod.GET)
@ResponseBody
public String handleRequest(SearchDTO search) {
    LOG.info("criteria: {}", search);
    return "OK";
}

প্রশ্ন:

http://localhost:8080/app/handle?id=353,234

ফলাফল:

[http-apr-8080-exec-7] INFO  c.g.g.r.f.w.ExampleController.handleRequest:59 - criteria: SearchDTO[id={353,234}]

আমি আসা করি এটা সাহায্য করবে :)

আপডেট / কোটলিন

কারণ বর্তমানে আমি কোটলিনের সাথে প্রচুর কাজ করছি যদি কেউ কোটলিনের অনুরূপ ডিটিওর সংজ্ঞা দিতে চান তবে নিম্নলিখিত ফর্মটি থাকতে হবে:

class SearchDTO {
    var id: Array<Long>? = arrayOf()

    override fun toString(): String {
        // to string implementation
    }
}

dataএই মত শ্রেণীর সাথে :

data class SearchDTO(var id: Array<Long> = arrayOf())

বসন্ত (বুটে পরীক্ষিত) উত্তরে অনুরোধের জন্য নিম্নলিখিত ত্রুটিটি প্রদান করে:

"'Java.lang.String []' প্রকারের মান 'প্রয়োজনীয় প্রকারে রূপান্তর করতে ব্যর্থ" java.lang.Long []'; নেস্টেড ব্যতিক্রম java.lang.Number FormatException: ইনপুট স্ট্রিংয়ের জন্য: 35 "353,234 \" "

ডেটা ক্লাসটি কেবলমাত্র নিম্নলিখিত অনুরোধের প্যারাম ফর্মের জন্য কাজ করবে:

http://localhost:8080/handle?id=353&id=234

সচেতন থাকুন!


1
ডিটিও ক্ষেত্রে "প্রয়োজনীয়" সেট করা কি সম্ভব?
সাধারণ

4
আমি স্প্রিং এমভিসি যাচাইকারীদের দিয়ে চেষ্টা করার পরামর্শ দিই। উদাহরণ: কোড java.net/frameworks/spring/…
নওক

এটি খুব কৌতূহলযুক্ত যে এর জন্য কোনও টীকা দেওয়ার দরকার নেই! আমি অবাক হই, এই অযৌক্তিকতার জন্য কি স্পষ্ট ভাষ্য আছে?
জেমস ওয়াটকিন্স

8

আমি খুব একই সমস্যা আছে। আসলে সমস্যাটি যত গভীর হয়েছিল আমি ভেবেছি। আমি jquery ব্যবহার করছি $.postযা Content-Type:application/x-www-form-urlencoded; charset=UTF-8ডিফল্ট হিসাবে ব্যবহার করে । দুর্ভাগ্যক্রমে আমি তার উপর ভিত্তি করে আমার সিস্টেমটি তৈরি করেছি এবং যখন আমার হিসাবে জটিল জটিল কোনও বিষয় প্রয়োজন@RequestParam এটি ঘটতে পারি না।

আমার ক্ষেত্রে আমি ব্যবহারকারীর পছন্দগুলি এমন কিছু সহ প্রেরণ করার চেষ্টা করছি;

 $.post("/updatePreferences",  
    {id: 'pr', preferences: p}, 
    function (response) {
 ...

ক্লায়েন্ট পক্ষের সার্ভারে প্রেরিত আসল কাঁচা তথ্য হ'ল;

...
id=pr&preferences%5BuserId%5D=1005012365&preferences%5Baudio%5D=false&preferences%5Btooltip%5D=true&preferences%5Blanguage%5D=en
...

হিসাবে পার্স করা;

id:pr
preferences[userId]:1005012365
preferences[audio]:false
preferences[tooltip]:true
preferences[language]:en

এবং সার্ভার পার্শ্ব হয়;

@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") UserPreferences preferences) {

    ...
        return someService.call(preferences);
    ...
}

আমি চেষ্টা করেছিলাম @ModelAttribute , সেটার / গেটার যুক্ত করেছি, এতে সমস্ত সম্ভাবনা রয়েছে allUserPreferences তবে কোনও সম্ভাবনা নেই কারণ এটি প্রেরিত ডেটাটিকে 5 টি প্যারামিটার হিসাবে স্বীকৃতি দেয় তবে বাস্তবে ম্যাপ করা পদ্ধতিতে মাত্র 2 পরামিতি রয়েছে। আমি বিজুর সমাধানও চেষ্টা করেছিলাম তবে যা ঘটে তা হ'ল বসন্তটি একটি ডিফল্ট কনস্ট্রাক্টর সহ একটি ইউজারপ্রাইফারেন্স অবজেক্ট তৈরি করে এবং ডেটা পূরণ করে না।

আমি ক্লায়েন্টের পক্ষ থেকে পছন্দগুলির JSon স্ট্রিং প্রেরণ করে সমস্যার সমাধান করেছি এবং এটি হ্যান্ডেল করছি যেন এটি সার্ভারের পাশের স্ট্রিং;

ক্লায়েন্ট:

 $.post("/updatePreferences",  
    {id: 'pr', preferences: JSON.stringify(p)}, 
    function (response) {
 ...

সার্ভার:

@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") String preferencesJSon) {


        String ret = null;
        ObjectMapper mapper = new ObjectMapper();
        try {
            UserPreferences userPreferences = mapper.readValue(preferencesJSon, UserPreferences.class);
            return someService.call(userPreferences);
        } catch (IOException e) {
            e.printStackTrace();
        }
}

সংক্ষেপে বলতে গেলে, আমি আরআরএসটি পদ্ধতির ভিতরে ম্যানুয়ালি রূপান্তরটি করেছি। আমার মতে কেন বসন্ত প্রেরিত ডেটা স্বীকৃতি দেয় না তা হ'ল সামগ্রী-প্রকার।


1
আমি ঠিক একই সমস্যাটি অনুভব করেছি, এবং এটি একইভাবে সমাধান করেছি। যাইহোক, আপনি কি আজকের মতো আরও ভাল সমাধান খুঁজে পেয়েছেন?
শাই এলকায়াম

1
আমারও ঠিক একই সমস্যা হচ্ছে। আমি @RequestMapping(method = POST, path = "/settings/{projectId}") public void settings(@PathVariable String projectId, @RequestBody ProjectSettings settings)
ক্লিনারটি ক্লিয়ার

4

যেহেতু প্রতিটি পোস্টের আওতায় ক্ষেত্রগুলি বাধ্যতামূলক পপ আপগুলি সেট করার প্রশ্ন থেকে আমি প্রয়োজনীয় ক্ষেত্রগুলি কীভাবে সেট করবেন সে সম্পর্কে একটি ছোট উদাহরণ লিখেছিলাম:

public class ExampleDTO {
    @NotNull
    private String mandatoryParam;

    private String optionalParam;

    @DateTimeFormat(iso = ISO.DATE) //accept Dates only in YYYY-MM-DD
    @NotNull
    private LocalDate testDate;

    public String getMandatoryParam() {
        return mandatoryParam;
    }
    public void setMandatoryParam(String mandatoryParam) {
        this.mandatoryParam = mandatoryParam;
    }
    public String getOptionalParam() {
        return optionalParam;
    }
    public void setOptionalParam(String optionalParam) {
        this.optionalParam = optionalParam;
    }
    public LocalDate getTestDate() {
        return testDate;
    }
    public void setTestDate(LocalDate testDate) {
        this.testDate = testDate;
    }
}

@RequestMapping(value = "/test", method = RequestMethod.GET)
public String testComplexObject (@Valid ExampleDTO e){
    System.out.println(e.getMandatoryParam() + " " + e.getTestDate());
    return "Does this work?";
}

0

যদিও উত্তরগুলি পড়ুন @ModelAttribute, @RequestParam,@PathParam এবং পছন্দগুলি বৈধ, একটি ছোট gotcha হয় আমি গাড়ীতে আঘাত করা হয়। ফলস্বরূপ পদ্ধতির পরামিতি একটি প্রক্সি যা স্প্রিংটি আপনার ডিটিওর চারপাশে আবৃত। সুতরাং, আপনি যদি নিজের প্রকারে নিজের কাস্টম প্রকারের প্রয়োজন হয় এমন প্রসঙ্গে এটি ব্যবহার করার চেষ্টা করেন তবে আপনি কিছু অপ্রত্যাশিত ফলাফল পেতে পারেন।

নিম্নলিখিতগুলি কাজ করবে না:

@GetMapping(produces = APPLICATION_JSON_VALUE)
public ResponseEntity<CustomDto> request(@ModelAttribute CustomDto dto) {
    return ResponseEntity.ok(dto);
}

আমার ক্ষেত্রে, জ্যাকসন বাইন্ডিং এ এটি ব্যবহারের চেষ্টা করার ফলে এ com.fasterxml.jackson.databind.exc.InvalidDefinitionException

আপনাকে dto থেকে একটি নতুন অবজেক্ট তৈরি করতে হবে।


0

হ্যাঁ, আপনি এটি একটি সহজ উপায়ে করতে পারেন। লাইন কোড নীচে দেখুন।

ইউআরএল - HTTP: // লোকালহোস্ট: 8080 / get / অনুরোধ / একাধিক / পরম / দ্বারা / মানচিত্র? নাম = 'এবিসি' & আইডি = '123'

 @GetMapping(path = "/get/request/header/by/map")
    public ResponseEntity<String> getRequestParamInMap(@RequestParam Map<String,String> map){
        // Do your business here 
        return new ResponseEntity<String>(map.toString(),HttpStatus.OK);
    } 

0

স্বীকৃত উত্তরটি কবজির মতো কাজ করে তবে বস্তুর যদি বস্তুর একটি তালিকা থাকে তবে এটি প্রত্যাশার মতো কাজ করবে না তাই কিছু খননের পরে এখানে আমার সমাধান।

এই থ্রেড পরামর্শ অনুসরণ করে , এখানে আমি কীভাবে করেছি।

  • সম্মুখভাগ: জমা দেওয়ার জন্য বেস 64 এ এনকোড করার চেয়ে আপনার অবজেক্টটিকে স্ট্রিংফাই করুন।
  • ব্যাকএন্ড: ডিকোড বেস 64 স্ট্রিং এর পরে স্ট্রিং জসনকে কাঙ্ক্ষিত বস্তুতে রূপান্তর করুন।

এটি পোস্টম্যানের সাথে আপনার এপিআই ডিবাগ করার জন্য সেরা নয় তবে এটি আমার জন্য প্রত্যাশা অনুযায়ী কাজ করছে।

মূল অবজেক্ট: {পৃষ্ঠা: 1, আকার: 5, ফিল্টার: [{ক্ষেত্র: "আইডি", মান: 1, তুলনা: "EQ"}

এনকোডযুক্ত বস্তু: eJWYWdlIjoxLCJzaXplIjo1LCJmaWx0ZXJzIjpbeyJmaWVsZCI6IMLkUGFyZW50IiwiY29tcGFyaXNvbiI6Ik5VTEwifV19

@GetMapping
fun list(@RequestParam search: String?): ResponseEntity<ListDTO> {
    val filter: SearchFilterDTO = decodeSearchFieldDTO(search)
    ...
}

private fun decodeSearchFieldDTO(search: String?): SearchFilterDTO {
    if (search.isNullOrEmpty()) return SearchFilterDTO()
    return Gson().fromJson(String(Base64.getDecoder().decode(search)), SearchFilterDTO::class.java)
}

এবং এখানে অনুসন্ধান ফিল্টারডিটিও এবং ফিল্টারডিটিও রয়েছে

class SearchFilterDTO(
    var currentPage: Int = 1,
    var pageSize: Int = 10,
    var sort: Sort? = null,
    var column: String? = null,
    var filters: List<FilterDTO> = ArrayList<FilterDTO>(),
    var paged: Boolean = true
)

class FilterDTO(
    var field: String,
    var value: Any,
    var comparison: Comparison
)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.