Create a txt file and make the browser download it at once - spring

#Controller
#RequiredArgsConstructor
#RequestMapping("/semantics")
public class SemanticsController {
private final SemanticsService semanticsService;
#PostMapping("/form-resuls")
#ResponseBody
public byte[] formResults(#RequestParam("value") String value) throws IOException {
List<String> phrases = semanticsService.addWordstatSyntax(value);
return null;
}
}
I'd like to form a filt out of these phrases (each phrase on a separate line).
And make the user's browser download it immediately (to their "Downloads" folder).
The name of the file will be "semantics.txt".
Could you help me understand how to do that?

Related

Customize Section title in Spring Auto Rest Docs

I want to customize Section "title" in auto-section.adoc[] file generated by Spring Auto Rest Docs. Spring Auto Rest Docs resolves section title using #title Javadoc tag on the method(if present) or from the method name (as mentioned in docs), but i can't inlcude #title in the Javadoc tag of method as the controller class is from other JAR, also I don't want the default generated method name. So, how to customize Section title in Spring Auto Rest Docs.
E.g. In auto generated auto-section.adoc[]
I don't want
=== Resolved Method Name
I want
=== Something else
Any help? Thanks.
Spring Auto REST Docs determines the title by looking at the #title tag and if this is not found, the method name is taken. There is currently no way to directly customize this behavior. If you can not modify the Javadoc, like in your case, you have to add the information via the snippet. There are at least two options:
Create a custom template. But then you are limited to the information available to the snippet and thus there are not a lot of alternatives to hard-coding text. See https://scacap.github.io/spring-auto-restdocs/#snippets-customization
Create a custom snippet. This gives you full control over everything and thus a snippet could be created that takes "Something else" as an input and uses it as the title. See https://scacap.github.io/spring-auto-restdocs/#snippets-custom to create custom snippets and https://scacap.github.io/spring-auto-restdocs/#snippets-section-custom-snippet to include custom snippets in the section snippet.
I achieved customizing section title in auto-section.adoc as below:
1) I created custom section snippet that extends SectionSnippet:
class CustomSectionSnippet extends SectionSnippet {
private final String title;
public CustomSectionSnippet(final Collection<String> sectionNames, final boolean skipEmpty,
final String title) {
super(sectionNames, skipEmpty);
this.title = title;
}
#Override
protected Map<String, Object> createModel(final Operation operation) {
final Map<String, Object> model = super.createModel(operation);
if (title != null) {
model.put("title", title);
}
return model;
}
}
2) And then the custom section builder that extends SectionBuilder:
class CustomSectionBuilder extends SectionBuilder {
private Collection<String> snippetNames = DEFAULT_SNIPPETS;
private final boolean skipEmpty = false;
private String title;
#Override
public CustomSectionBuilder snippetNames(final String... snippetNames) {
this.snippetNames = Arrays.asList(snippetNames);
return this;
}
public CustomSectionBuilder sectionTitle(final String title) {
this.title = title;
return this;
}
#Override
public SectionSnippet build() {
return new CustomSectionSnippet(snippetNames, skipEmpty, title);
}
}
3) And then used it like this:
#Test
void testApi() throws Exception {
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", "test");
this.mockMvc.perform(post("/api")
.params(params)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(commonDocumentation(
new CustomSectionBuilder()
.sectionTitle("Something else") // <-- custom section title
.snippetNames(
AUTO_AUTHORIZATION,
AUTO_REQUEST_FIELDS,
REQUEST_HEADERS,
REQUEST_PARAMETERS,
RESPONSE_FIELDS,
CURL_REQUEST,
HTTP_RESPONSE)
.build()
));
}
And now I'm able to pass Something else as a section title that will be included in the auto generated auto-section.adoc file.
Thanks #florian-benz for help :)

How to disable spring boot parameter split

We have many #RestController receiving phrases in common language written by users. Phrases can be very long and contains punctuation, like periods and, of course, commas.
Simplified controller example:
#RequestMapping(value = "/countphrases", method = RequestMethod.PUT)
public String countPhrases(
#RequestParam(value = "phrase", required = false) String[] phrase) {
return "" + phrase.length;
}
Spring boot default behaviour is to split parameters values at comma, so the previous controller called with this url:
[...]/countphrases?phrase=john%20and%20me,%20you%and%her
Will return "2" istead of "1" like we want. In fact with the comma split the previous call is equivalent to:
[...]/countphrases?phrase=john%20and%20me&phrase=you%and%her
We work with natural language and we need to analyze phrases exactly how the users wrote them and to know exactly how many they wrote.
We tried this solution: https://stackoverflow.com/a/42134833/1085716 after adapting it to our spring boot version (2.0.5):
#Configuration
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addFormatters(FormatterRegistry registry) {
// we hoped this code could remove the "split strings at comma"
registry.removeConvertible(String.class, Collection.class);
}
}
But it doesn't work.
Anyone know how to globally remove the "spring boot split string parameters at comma" behaviour in spring boot 2.0.5?
I find the solution.
To override a default conversion we must add a new one. If we remove the old one only it doesn't work.
The correct (example) code should be:
#Configuration
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addFormatters(FormatterRegistry registry) {
registry.removeConvertible(String.class, String[].class);
registry.addConverter(String.class, String[].class, noCommaSplitStringToArrayConverter());
}
#Bean
public Converter<String, String[]> noCommaSplitStringToArrayConverter() {
return new Converter<String, String[]>() {
#Override
public String[] convert(String source) {
String[] arrayWithOneElement = {source};
return arrayWithOneElement;
}
};
}
}
This way any controller like the one in the main question will not split parameters values:
[...]/countphrases?phrase=a,b will return 1 (and fq=["a,b"])
[...]/countphrases?phrase=a,b&phrase=c,d will return 2 (and fq=["a,b", "c,d"])
Replacing your formatter registry with a completely new list could make you loose some needed default formatters that would come with the framework. This will also disable all String-To-Collections parsing for the entire application, on every endpoint, such that if you want to a request filter such as the following at another endpoint, it won't work:
identifiers = 12,34,45,56,67
Solution:
Just change your delimiter into something else... # or ; or $
identifiers = 12;23;34;45;56
This is what I have been doing, so I don't mess with all the goodies in the formatter registry.

Spring Boot Redirecting to another controller method from current controller method

Hi all am new to spring boot. Am stuck in the middle of my learning path. I have two controllers(#Controller) with some methods define in them. Am submitting form data to a method in index controller and wants to move to the method in home controller if form submission gets successful(on succesfull login). while loading http://localhost:9090/method of index controller it loads all the static content correctly, but when i redirectreturn "redirect:/dashboard/index" then it navigates to http://localhost:9090/dashBoard/index. And /dashboard/index method is as follow
#Controller
public class HomeController {
#GetMapping(value = "/dashBoard/index")
public String hello(Model model, #RequestParam(value = "name", required = false, defaultValue = "World") String name) {
model.addAttribute("name", name);
return "index";
}
}
this method return "index" which is .jsp page but redirecting to this method changes static content path like http://localhost:9090/dashBoard/assets/images/avatar/1.jpg
it seems like appending /dashBoard/ in path of static content. Am not understanding what to do please help. Am adding my project properties and structure please have a look
application.properties
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.resources.static-locations=file:/var/www/static,classpath:static
spring.mvc.static-path-pattern=/resources/**
server.port=9090
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57InnoDBDialect
spring.jackson.serialization.fail-on-empty-beans=false
main class
[#SpringBootApplication
#EnableAutoConfiguration
public class SchoolpageApplication extends SpringBootServletInitializer {
public static void main(String\[\] args) {
SpringApplication.run(SchoolpageApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SchoolpageApplication.class);
}
}
Project Structure
Static content path
#Controller
#RequestMapping("/dashBoard")
public class HomeController {
#GetMapping("index")
public String hello(Model model, #RequestParam(value = "name", required = false, defaultValue = "World") String name) {
model.addAttribute("name", name);
return "index";
}
}
You could try this method, everytime you get throught an url with /dashboard you will get inside this controller, and you can control every option you want with the next income like /foo (in this case /index) and in the return it will get you into /dashboard/+your return value(in this case index).
I´m not an expert with spring boot, I´m pretty new with it too but I hope this can help you.

discussion about #RequestParam and #RequestBody

I have a class:
public class user{
private String id;
private MultiPartFile file;
**Getters And Setters**
}
And in the Controller:
#PostMapping(value="/upload)
public void upload(User user){
}
In the front end I post data with form-data.I can get the user object.
But when I add #RequestBody and #RequestParam,it can't works.
in my opinion,#RequestParam is used to binding parameter to simple class . when I use #RequestBody ,spring will find HttpMessageConverter to convert http request body to class.But I'm not sure about that.Does anyone can explain to me?
So, I believe we are talking about org.springframework.web.multipart.MultipartFile, which is to be used together with #RequestParam variable. The mechanism is somewhat special in this case.
I had a similar problem, and what I ended up using was org.springframework.web.multipart.commons.CommonsMultipartResolver. From frontend I've constructed multipart request with two parts, in your scenario it could be user (containing just JSON data) and file (containing the file itself), e.g.:
#PostMapping(value="/upload")
public void upload(#RequestParam("user") User user, #RequestParam("file") MultipartFile file){
...
}
But then, you need to configure custom serialization of the User part, which can be done using org.springframework.web.multipart.commons.CommonsMultipartResolver. You can configure it using bean config like this:
#Configuration
public class MappingConfig {
#Order(Integer.MIN_VALUE)
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
#Bean
public Converter<String, User> stringToUser() {
return new Converter<String, User>() {
#Override
public User convert(String jsonString) {
return new Gson().fromJson(jsonString, User.class);
}
};
}
...
}
Also, as you can see I am using Gson manually, I couldn't find a better way how to do it. Also, it doesn't play with Java 8 lambdas, so it cannot be shortened (because of explicit types are needed for it to work).
I hope that this will at least points you to a right path.

#RestController removes spaces in string

I have found an interesting bug/feature while writing webservice. I am returning JSON data for selection filter in frontend. Then these selections are returned me back to get data. I am sending it to a database so I need exactly the same format.
Problem is when there are more then two spaces in its name. On JSON output it removes any number of spaces and leaves only one. But I need all of them. How can I force RestController to leave there all spaces?
#RestController
#RequestMapping("/")
public class FilterController {
private static final Logger log = Logger.getLogger(FilterController.class);
#Autowired
SentimentService sentimentService;
#RequestMapping(value="/filter", method=RequestMethod.GET)
public Filter getValues(#RequestParam(value="sources", defaultValue="50") int sourceNb) {
Filter filter = sentimentService.filterGetValue();
return filter;
}
}
This is my controller. Filter is object with tree structure. One of them is Product layer. I even added sysout there. The spaces are saved in the object but not passed to JSON output.
public class Product {
private String name;
public String getName() {
System.out.println("Name: " + name); // it really has two spaces there
return name;
}
public void setName(String value) {
this.name = value;
}
}
Is there any annotation I need to add to my class variable to be left as it is? I couldn't find anything useful so I just hope that it can be done easily. Thanks.

Resources