S’il y a quelque chose que j’apprécie particulièrement dans Spring MVC, c’est bien la facilité et la rapidité à mettre en place des API REST. Par défaut, Spring MVC propose le support du XML, JSON, RSS, Atom et images.

L’ajout du support d’un nouveau format est extrêmement simple. Pour cela, il suffi d’implémenter l’interface AbstractHttpMessageConverter. Voici ci-dessous l’implémentation pour le support des messages HTTP au format CSV :

@Component
public class CsvMessageConverter extends AbstractHttpMessageConverter<List<?>> {
  public static final MediaType MEDIA_TYPE = new MediaType("text", "csv", Charset.forName("utf-8"));

  public CsvMessageConverter() {
    super(MEDIA_TYPE);
  }

  @Override
  protected boolean supports(Class<?> clazz) {
    return List.class.isAssignableFrom(clazz);
  }

  @Override
  protected void writeInternal(List<?> response, HttpOutputMessage output)
      throws IOException, HttpMessageNotWritableException {
    OutputStream out = output.getBody();
    CsvWriter writer = new CsvWriter(new OutputStreamWriter(out));
    writer.writeAllRecords(reponse);
    writer.flush();
    writer.close();
  }

  @Override
  protected List<?> readInternal(Class<? extends List<?>> request,
      HttpInputMessage input) throws IOException,
      HttpMessageNotReadableException {
    InputStream in = input.getBody();
    CsvReader reader = new CsvReader(new InputStreamReader(in));
    List<?> records = reader.readAllRecords();

    return records;
  }
}

Une fois le convertisseur implémenté, il faut le déclarer dans la configuration de Spring MVC :

<mvc:annotation-driven>
  <mvc:message-converters>
    <beans:bean class="com.mycompany.myproject.http.converter.CsvMessageConverter" />
  </mvc:message-converters>
</mvc:annotation-driven>

Maintenant, votre application est prête à générer ou recevoir des requêtes HTTP au format CSV très simplement comme dans le contrôleur suivant :

@Controller
public class StatsController {
  @Autowired
  private StatsService statsService;

  @RequestMapping(
    value = "/stats/{year}/{month}.csv",
    method = RequestMethod.GET,
    produces = "text/csv")
  @ResponseBody
  public List<Stats> getAllStats(@PathVariable("year") int year,
      @PathVariable("month") int month) throws IOException {
    return statsService.findAllStats(year, month);
  }

  @RequestMapping(
    value = "/stats/{year}/{month}",
    method = RequestMethod.POST,
    consumes = "text/csv")
  public List<Stats> saveAllStats(@PathVariable("year") int year,
      @PathVariable("month") int month, @RequestBody List<Stats> stats) {
    statsService.saveAllStats(year, month, stats);

    return statsService.findAllStats(year, month);
  }
}

Si vous souhaitez aller plus loin, vous pouvez bien-entendu consulter la JavaDoc de HttpMessageConverter.

Vous êtes donc maintenant capable de proposer le téléchargement de données au format CSV très simplement dans votre application. Libre à vous de reprendre ce convertisseur ou d’en implémenter d’autres. Vous avez peut-être besoin d’un convertisseur Protobuf ? 😛