Stripes MVC Model Data - java

I am experienced with Spring MVC and am trying out Stripes to decide whether to try it out for a new project.
In Spring MVC I would prepare model data and pass it to the view by adding it to a map in the ModelAndView instance created by my controller. I am having trouble finding the equivalent of this for Stripes.
It seems like the closest parallel is to have an ActionBean prepare my model data and add it to the HttpSession. A ForwardRedirect is used to load the view and the data is accessed from the session.
Is there better support for a front controller provided by Stripes, or is this a totally different design principle than Spring MVC? (ie I have to invoke methods from the view using EL to retrieve data, as some of the examples do)
Thanks!

A typical MVC design in Stripes would look like something like the code below.
The JPA entity is automaticaly loaded by a Stripes interceptor provided by Stripersist (but this can also easily implemented on your own if you wish). Thus in this example, requesting http://your.app/show-order-12.html will load a order with id 12 from the database and will show it on the page.
Controller (OrderAction.java):
#UrlBinding("/show-order-{order=}.html")
public class OrderAction implements ActionBean {
private ActionBeanContext context;
private Order order;
public ActionBeanContext getContext() {
return context;
}
public void setContext(ActionBeanContext context) {
this.context = context;
}
public void setOrder(Order order) {
this.order = order;
}
public String getOrder() {
return order;
}
#DefaultHandler
public Resolution view() {
return new ForwardResolution(“/WEB-INF/jsp/order.jsp”);
}
}
View (order.jsp):
<html><body>
Order id: ${actionBean.order.id}<br/>
Order name: ${actionBean.order.name)<br/>
Order total: ${actionBean.order.total)<br/>
</body></html>
Model (Order.java):
#Entity
public class Order implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer total;
public String getName() {
return name;
}
public Integer getTotal() {
return total;
}
}
BTW there is an really excellent short(!) book on Stripes that covers all these things:
Stripes: ...and Java Web Development Is Fun Again

Okay I have figured it out. Attributes added to the HttpServletRequest (retrieved from context) ARE available in the page receiving the ForwardRedirect
IE
context.getRequest().setAttribute("attr1", "request attribute 1");
return new ForwardResolution("/WEB-INF/pages/hello.jsp");
In hello.jsp
${attr1}
is available... yay!

There is on one nice solution for nopCommerce 3.20 (MVC). It's a payment plugin supporting, authorize, authorize/capture, refund and partially refund. PCI compliance included, no CC info is stored on db
http://shop.wama-net.com/en/stripe-payment-plugin-for-nopcommerce
Jacky

Related

How to get custom dynamic attributes for entity with JPA?

I make a social network and have a post entity that looks like that:
#Entity
public class PostModel {
/* ... */
private String text;
#ManyToMany
private Set<UserModel> likedBy;
}
and a DTO object:
public class PostDto {
/* ... */
private String text;
private Boolean isLikedByMe;
}
To get PostModel's, I use the Specifications API and JpaSpecificationExecutor.
How can I find out the value of the isLikedByMe field for DTO? I can get a UserModel based on username in principal of current Authentication. But what to do next?
I would not like to use Lazy Loading with #PostLoad for this, since with large requests for posts it will seriously slow down the execution.
I also wouldn't want to give up on the Specifications API because of the complexity of some of the queries I create with them.

How to use Mongo Auditing and a UUID as id with Spring Boot 2.2.x?

I would like to have Documents stored with an UUID id and createdAt / updatedAt fields. My solution was working with Spring Boot 2.1.x. After I upgraded from Spring Boot 2.1.11.RELEASE to 2.2.0.RELEASE my test for MongoAuditing failed with createdAt = null. What do I need to do to get the createdAt field filled again?
This is not just a testproblem. I ran the application and it has the same behaviour as my test. All auditing fields stay null.
I have a Configuration to enable MongoAuditing and UUID generation:
#Configuration
#EnableMongoAuditing
public class MongoConfiguration {
#Bean
public GenerateUUIDListener generateUUIDListener() {
return new GenerateUUIDListener();
}
}
The listner hooks into the onBeforeConvert - I guess thats where the trouble starts.
public class GenerateUUIDListener extends AbstractMongoEventListener<IdentifiableEntity> {
#Override
public void onBeforeConvert(BeforeConvertEvent<IdentifiableEntity> event) {
IdentifiableEntity entity = event.getSource();
if (entity.isNew()) {
entity.setId(UUID.randomUUID());
}
}
}
The document itself (I dropped the getter and setters):
#Document
public class MyDocument extends InsertableEntity {
private String name;
}
public abstract class InsertableEntity extends IdentifiableEntity {
#CreatedDate
#JsonIgnore
private Instant createdAt;
}
public abstract class IdentifiableEntity implements Persistable<UUID> {
#Id
private UUID id;
#JsonIgnore
public boolean isNew() {
return getId() == null;
}
}
A complete minimal example can be find here (including a test) https://github.com/mab/auditable
With 2.1.11.RELEASE the test succeeds with 2.2.0.RELEASE it fails.
For me the best solution was to switch from event UUID generation to a callback based one. With the implementation of Ordered we can set the new callback to be executed after the AuditingEntityCallback.
public class IdEntityCallback implements BeforeConvertCallback<IdentifiableEntity>, Ordered {
#Override
public IdentifiableEntity onBeforeConvert(IdentifiableEntity entity, String collection) {
if (entity.isNew()) {
entity.setId(UUID.randomUUID());
}
return entity;
}
#Override
public int getOrder() {
return 101;
}
}
I registered the callback with the MongoConfiguration. For a more general solution you might want to take a look at the registration of the AuditingEntityCallback with the `MongoAuditingBeanDefinitionParser.
#Configuration
#EnableMongoAuditing
public class MongoConfiguration {
#Bean
public IdEntityCallback registerCallback() {
return new IdEntityCallback();
}
}
MongoTemplate works in the following way on doInsert()
this.maybeEmitEvent - emit an event (onBeforeConvert, onBeforeSave and such) so any AbstractMappingEventListener can catch and act upon like you did with GenerateUUIDListener
this.maybeCallBeforeConvert - call before convert callbacks like mongo auditing
like you can see in source code of MongoTemplate.class src (831-832)
protected <T> T doInsert(String collectionName, T objectToSave, MongoWriter<T> writer) {
BeforeConvertEvent<T> event = new BeforeConvertEvent(objectToSave, collectionName);
T toConvert = ((BeforeConvertEvent)this.maybeEmitEvent(event)).getSource(); //emit event
toConvert = this.maybeCallBeforeConvert(toConvert, collectionName); //call some before convert handlers
...
}
MongoAudit marks createdAt only to new entities by checking if entity.isNew() == true
because your code (UUID) already set the Id the createdAt is not populated (the entity is not considered new)
you can do the following (order by best to worst):
forget about the UUID and use String for your id, let the mongo itself create and manage it's entities ids (this how MongoTemplate actually works lines 811-812)
keep the UUID at the code level, convert from/to String when inserting and retrieving from the db
create a custom repository like in this post
stay with 2.1.11.RELEASE
set the updateAt by GenerateUUIDListener as well as id (rename it NewEntityListener or smth), basically implement the audit
implement a new isNew() logic that don't depends only on the entity id
in version 2.1.11.RELEASE the order of the methods was flipped (MongoTemplate.class 804-805) so your code worked fine
as an abstract approach, the nature of event is to be sort of send-and-forget (async compatible), so it's a very bad practice to change the object itself, there is NO grantee for order of computation, if any
this is why the audit build on callbacks and not events, and that's why Pivotal don't (need to) keep order between versions

Spring boot - partial update best practise?

I am using Spring boot v2 with mongo database. I was wondering what is the best way to do partial updates on the data model. Say I have a model with x attributes, depending on the request I may only want to update 1, 2 , or x of them attributes. Should I be exposing an end point for each type of update operation, or is it possible to expose one end pint and do it in a generic way? Note I will need to be able to validate the contents of the request attributes (e.g tel no must be numbers only)
Thanks,
HTTP PATCH is a nice way to update a resource by specifying only the properties that have changed.
The following blog explain it very well
You can actually expose just one endpoint. This is the situation I had a few months ago:
I wanted people to modify any (or even all)fields of a Projects document (who am I to force the users to manually supply all fields lol). So I have my Model,
Project.java:
package com.foxxmg.jarvisbackend.models;
//imports
#Document(collection = "Projects")
public class Project {
#Id
public String id;
public String projectTitle;
public String projectOverview;
public Date startDate;
public Date endDate;
public List<String> assignedTo;
public String progress;
//constructors
//getters & setters
}
I have my repository:
ProjectRepository.java
package com.foxxmg.jarvisbackend.repositories;
//imports
#Repository
public interface ProjectRepository extends MongoRepository<Project, String>, QuerydslPredicateExecutor<Project> {
//please note, we are going to use findById(string) method for updating
Project findByid(String id);
//other abstract methods
}
Now to my Controller, ProjectController.java:
package com.foxxmg.jarvisbackend.controllers;
//import
#RestController
#RequestMapping("/projects")
#CrossOrigin("*")
public class ProjectController {
#Autowired
private ProjectRepository projectRepository;
#PutMapping("update/{id}")
public ResponseEntity<Project> update(#PathVariable("id") String id, #RequestBody Project project) {
Optional<Project> optionalProject = projectRepository.findById(id);
if (optionalProject.isPresent()) {
Project p = optionalProject.get();
if (project.getProjectTitle() != null)
p.setProjectTitle(project.getProjectTitle());
if (project.getProjectOverview() != null)
p.setProjectOverview(project.getProjectOverview());
if (project.getStartDate() != null)
p.setStartDate(project.getStartDate());
if (project.getEndDate() != null)
p.setEndDate(project.getEndDate());
if (project.getAssignedTo() != null)
p.setAssignedTo(project.getAssignedTo());
return new ResponseEntity<>(projectRepository.save(p), HttpStatus.OK);
} else
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
That will allow partial update in MongoDB with Spring Boot.
If you are using Spring Data MongoDB, you have two options either use the MongoDB Repository or using the MongoTemplate.

Spring simple example: where create list of beans in JavaConfig?

I'm learning Spring but I don't understand where I have to fill my structure... for example, I want a list of Teams where each team have a list of players.
This is the code, i have my TeamApplication:
#SpringBootApplication
public class TeamApplication {
public static void main(String[] args) {
SpringApplication.run(TeamApplication.class, args);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Team team = context.getBean(Team.class);
Player player = context.getBean(Player.class);
}
}
then I have AppConfig:
#Configuration
public class AppConfig {
#Bean
public Team team() {
return new Team();
}
#Bean
public Player player() {
return new Player();
}
}
so Player is:
public class Player {
private static final Logger LOG = LoggerFactory.getLogger(Player.class);
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#PostConstruct
public void init() {
LOG.info("Player PostConstruct");
}
#PreDestroy
public void destroy() {
LOG.info("Player PreDestroy");
}
}
and Team is:
public class Team {
private static final Logger LOG = LoggerFactory.getLogger(Team.class);
private String name;
private List<Player> listPlayer;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Player> getListPlayer() {
return listPlayer;
}
public void setListPlayer(List<Player> listPlayer) {
this.listPlayer = listPlayer;
}
#PostConstruct
public void init() {
LOG.info("Team PostConstruct");
}
#PreDestroy
public void destroy() {
LOG.info("Team PreDestroy");
}
}
Now:
- Where I have to fill those lists? in PostConstruct? But in this way i have always the same datas... in an simple Java application I first create players:
Player p1 = new Player();
p1.setName("A");
p1.setAge(20);
Player p2 = new Player();
p1.setName("B");
p1.setAge(21);
Player p3 = new Player();
p1.setName("C");
p1.setAge(22);
Then I create my teams:
List<Person> l1 = new LinkedList<>();
l1.add(p1);
l1.add(p2);
Team t1 = new Team();
t1.setListPlayer(l1);
List<Person> l2 = new LinkedList<>();
l2.add(p3);
Team t2 = new Team();
t1.setListPlayer(l2);
so... in Spring:
Where can I init my players (in PostConstruct I will get always the same name/age)?
Where have I to create my listTeam? After getBean in TeamApplication?
Kind regards!
I've created a quick example project on GitHub. I need to emphasize that this is not a production ready code and you shouldn't follow it's patterns for I did't refactor it to be pretty but understandable and simple instead.
First you don't have to define the set of teams and players. As you said the data will be loaded from DB, so let the users do this work. :) Instead, you need to define the services (as spring beans) which contain the business logic for the users to do their task.
How does Spring know my db table structure and the DB table <-> Java object mapping? If you want to persist your teams and players some DB, you should mark them with annotations for Spring. In the example project I put the #Entity annotation to them so Spring will know it has to store them. Spring use convention over configuration so if I don't define any db table names, Spring will generate some from the entity class names, in this case PLAYER, TEAM and TEAM_PLAYERS. Also I annotated the Java class field I wanted to store with the following annotations:
#Column: this field will be stored in a DB column. Without any further config Spring will generate the name of it's column.
#Id and #GeneratedValue: Spring will auto generate the id of the persisted entities and store it's value in this annotated field.
#OneToMany: this annotation tells Spring to create a relation between two entities. Spring will create the TEAM_PLAYERS join table because of this annotation, and store the team-player id pairs in it.
How does Spring know the database's URL? As I imported H2 db in maven's pom.xml Spring will use it, and without any configuration it'll store data in memory (which will lost between app restarts). If you look at the application.yaml you can find the configuration for the DB, and Spring'll do the same. If you uncomment the commented lines Spring'll store your data under your home directory.
How does Spring sync these entities to the DB? I've created two repositories and Spring'll use them to save, delete and find data. They're interfaces (PlayerRepository and TeamRepository) and they extend CrudRepository interface which gives them some basic CRUD operations without any further work.
So far so good, but how can the users use these services? I've published these functionalities through HTTP endpoints (PlayerController and TeamController). I marked them as #RestControllers, so spring will map some HTTP queries to them. Through them users can create, delete, find players and teams, and assign players to teams or remove one player from a team.
You can try this example if you build and start it with maven, and send some queries to these endpoints by curl or by navigating to http://localhost:8080/swagger-ui.html page.
I've done some more configuration for this project but those are not relevant from the aspect of your question. I haven't explained the project deeper but you can make some investigation about my solutions and you can find documentations on Spring's site.
Conclusion:
My Spring managed classes are:
#Entity: Player, Team
Repository: PlayerRepository, TeamRepository
#RestController: PlayerController, TeamController
The flow of a call: User -(HTTP)-> #RestController -> Repository(Entity) -> DB
Spring isn't really meant for defining beans like your Player and Team class, where they are basically POJOs that will likely be different in each instance. Where Spring beans really shine are in defining singletons that will be injected int other beans or components, such as a Controller, a service, or similar.
That said, it is possible to define beans that are not singletons. Just change the scope of the bean to prototype, like so:
#Bean
#Scope("prototype")
public Team team() {
return new Team();
}

How to use a single transaction for a Wicket / Spring page view?

My previous question How to wrap Wicket page rendering in a Spring / Hibernate transaction? has led me to thinking about transaction demarcation in Wicket.
Whilst the example there was easily solved by moving business logic down into a Spring-managed layer, there are other places where this is not possible.
I have a generic DAO class, implemented by Hibernate, with
public class HibernateDAO<T> implements DAO<T> {
protected final Class<T> entityClass;
private final SessionFactory sessionFactory;
#Transactional
public T load(Serializable id) {
return (T) getSession().get(entityClass, id);
}
#Transactional
public void saveOrUpdate(T object) {
getSession().saveOrUpdate(object);
}
}
and a generic model to fetch it
public class DAOEntityModel<T> extends LoadableDetachableModel<T>{
private DAO<T> dao;
private final Serializable id;
public DAOEntityModel(DAO<T> dao, Serializable id) {
this.dao = dao;
this.id = id;
}
public <U extends Entity> DAOEntityModel(DAO<T> dao, U entity) {
this(dao, entity.getId());
}
public Serializable getId() {
return id;
}
#Override
protected T load() {
return dao.load(id);
}
}
Now I have a minimal form that changes an entity
public class ScreenDetailsPanel extends Panel {
#SpringBean(name="screenDAO") private DAO<Screen> dao;
public ScreenDetailsPanel(String panelId, Long screenId) {
super(panelId);
final IModel<Screen> screenModel = new DAOEntityModel<Screen>(dao, screenId);
Form<Screen> form = new Form<Screen>("form") {
#Override protected void onSubmit() {
Screen screen = screenModel.getObject();
dao.saveOrUpdate(screen);
}};
form.add(
new TextField<String>("name", new PropertyModel<String>(screenModel, "name")));
add(form);
}
}
So far so good - thanks for sticking with it!
So my issue is this - when the form is submitted, the PropertyModel will load the screenModel, which will happen in the transaction delineated by the #Transactional dao.load(id). The commit of the changes will when the (different) transaction started for dao.saveOrUpdate(object) is committed. In between these times all bets are off, so that the object may no longer exist in the DB to be committed.
I'm never entirely sure with DB code and transactions. Should I just shrug this off as unlikely, although I could construct other more complicated but more dangerous scenarios? If not I can't see how to demarcate the whole page logic in a single transaction, which is what my instinct tells me I should be aiming for.
Typically you would solve this by putting the #Transactional annotation on a service-level class, used by your front-end layer code, which wraps around the DAO operations - so that the load and save happens within the same transaction. In other words, you can solve this by creating a layer of code between the form and the DAO code, a "service layer", which provides the business-level logic and hides the presence of DAOs from the presentation layer.
I've not yet implemented it, but I'm pretty sure that #ireddick solution in How to control JPA persistence in Wicket forms? of lazily starting a tx in in the Wicket request cycle is the best solution here. I'm going to accept this proxy for it to stop Stack Overflow nagging me to accept an answer.

Categories