How do I change my controller into a REST controller? From Thymeleaf to Vue.js - spring

For my university project, I have an up and running SpringBoot project using Thymeleaf, but I would now like to use Vue.js instead for my front end. To do this, I am wanting to change my controllers into REST Controllers but I'm struggling with how to go about that.
Here is an example of a method within the controller:
public String showQuiz(#PathVariable String subject, Model model) {
Session session = new Session();
session.setStart_time(new Timestamp(System.currentTimeMillis()));
List<Question> questions = questionService.getAllQuestionsBySubject(subject);
Quiz quiz = new Quiz(subject, questions, session);
session.setQuiz(quiz);
session.setScore(0);
ContextController.getEmployee().setSession(session);
session.setEmployeeId(ContextController.getEmployee().getId());
session.setEmployeeName(ContextController.getEmployee().getUsername());
ContextController.setSession(session); //optional shared context
sessionService.saveSession(session);
ContextController.questions = questions;
model.addAttribute("questions", questions);
AnswersDTO answersDto = new AnswersDTO();
model.addAttribute("answersDto", answersDto);
model.addAttribute("employee", ContextController.getEmployee());
return "quiz";
}
How would I convert the code above to return JSON?

Annotate your controller class #RestController. Return your data object wrapped in a org.springframework.http.ResponseEntity.
return ResponseEntity.ok().body(myDataObject);

Related

Session in Spring Rest

Hello i have a problem with session in spring rest i got everytime null in my session, this is my class
#GetMapping("/shoppingCart/addProduct/{productId}")
public ResponseEntity<Cart> addProductToCart(#PathVariable("productId") Long productId,HttpServletRequest request) throws AppException {
Product product = productService.getProduct(productId);
Cart cart= (Cart) request.getSession().getAttribute("myCart");
// If null, create it.
if (cart == null) {
cart = new Cart();
request.getSession().setAttribute("myCart", cart);
}
cart.addProduct(product, 1);
return new ResponseEntity<>(cart,HttpStatus.CREATED);
}
#GetMapping("/shoppingCart")
public ResponseEntity<Cart> shoppingCart(HttpServletRequest request) {
cart = (Cart) request.getSession().getAttribute("myCart");
return new ResponseEntity<>(cart,HttpStatus.CREATED);
}
this line request.getSession().getAttribute("myCart") returns null, and also when i add a product in my cart it saves in session for the first time after which when ever i try to add another product, my session is empty.
Thank you
RestFul services are inherently designed to be stateless, hence you should not be making use of session in a Rest API in the first place. But if you are somehow required to make use of the session as per you business logic then you should make use of Spring MVC instead of REST i.e. you should use #Controller annotation in the class and not #RestController.

views in thymeleaf spring boot templates sub folder

I am using thymeleaf in spring boot, and have several views. I don't want to keep all the views in the same folder which is src/main/resources/templates by default.
Is it possible to move some of the view in src/main/resources/templates/folder1, and I will pass "folder1/viewname" to access that page?
When I tried http://localhost:8080/folder1/layout1 it didn't found my html in src/main/resources/templates/folder1/, but when I move the html in templates main folder src/main/resources/templates/, http://localhost:8080/layout1 worked fine.
My controller class looks like:
#RequestMapping(value = "{pagename}", method = RequestMethod.GET)
public String mf42_layout1(#PathVariable String pagename) {
return pagename;
}
So, I thought if I pass layout1, it will look int the templates, and if I say "a/layout1", it will look in /layout folder
Thanks,
Manish
Basically, your request mapping and the name of your view are decoupled, you just need to pay attention to the syntax.
For instance, with
#RequestMapping(value = "/foobar", method = RequestMethod.GET)
public String mf42_layout1() {
return "layout1";
}
a request to http://localhost:8080/foobar will render the template located in src/main/resources/templates/layout1.html.
It also works if you put your templates on a subfolder, as long as you provide the correct path to the view:
#RequestMapping(value = "/foobar", method = RequestMethod.GET)
public String mf42_layout1() {
return "a/layout1";
}
A request to http://localhost:8080/foobar will render the template located in src/main/resources/templates/a/layout1.html.
You can also parameterized the url endpoint with #PathVariable:
#RequestMapping(value = "/foobar/{layout}", method = RequestMethod.GET)
public String mf42_layout1(#PathVariable(value = "layout") String layout) { // I prefer binding to the variable name explicitely
return "a/" + layout;
}
Now a request to http://localhost:8080/foobar/layout1 will render the template in src/main/resources/templates/a/layout1.html and a request to http://localhost:8080/foobar/layout2 will render what's in src/main/resources/templates/a/layout2.html
But beware the forward slash acts as a separator in URLs, so with your controller:
#RequestMapping(value = "{pagename}", method = RequestMethod.GET)
public String mf42_layout1(#PathVariable String pagename) {
return pagename;
}
My guess is when you hit http://localhost:8080/a/layout1 pagename receives "a" and "layout1" is not caught. So the controller probably tries to render the contents of src/main/resources/templates/a.html
The Spring MVC reference extensively describes how to map requests, you should read it carefully.
I faced similar template not found issue when running the application in a Linux server. I was using the path as "return "/a/layout1". This worked fine in a local windows PC, but I had to remove the starting "/" to make it work in a Linux box(i.e. "return "a/layout1").

Calling TableController.Lookup() from one controller on another controller fails

In an Azure Mobile App using the .NET backend, I need one controller to look up an entity handled by a second controller. For example, in the Todo Quickstart project from the Azure team, imagine adding a UserController which handles user management. In TodoItemController, I need to call UserController.GetUser(id) to check if a user is authorized to post a new TodoItem.
In TodoItemController.cs:
var userController = new UserController();
var user = userController.GetUser("12345");
if (user.IsAuthorized)
{
// Insert TodoItem
}
The above code throws an exception when TableController.Lookup() is called in UserController.GetUser(). The exception says that the request parameter cannot be null. My guess is that something is missing because I created the UserController myself, instead of it being created by the framework.
How can I make this work?
This appears to work in TodoItemController.cs:
var context = new todoProjectContext();
var userDomainManager = new EntityDomainManager<User>(context, Request);
var user = userDomainManager.Lookup(id).Queryable.FirstOrDefault();
if (user.isAuthorized)
{
// Insert item
}
Not sure it's the best solution though.

how to achieve MVC in my Zend Framework

currently i am doing a project in zend the way i am doing is working perfectly but i am sure its not the way i am suppose to do i mean i am not following MVC and i want to apply MVC in my zend app.
i am pasting code of one simple module which will describe what i am doing .kindly correct me where i am making faults.
my controller
class ContactsController extends Zend_Controller_Action{
public function contactsAction(){
if(!Zend_Auth::getInstance()->hasIdentity()){
$this->_redirect('login/login');
}
else{
$request = $this->getRequest();
$user = new Zend_Session_Namespace('user');
$phone_service_id = $user->p_id;
$instance = new Contacts();
$select = $instance->Get_Contacts($p_id);
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
$paginator = new Zend_Paginator($adapter);
.
.
//more code
}
plz note this 2 line in my controller
$instance = new Contacts();
$select = $instance->Get_Contacts($pid);
this is my contacts class in models
class Contacts extends Zend_Db_Table{
function Get_Contacts($p_id){
$DB = Zend_Db_Table_Abstract::getDefaultAdapter();
$select = $DB->select()
->from('contact', array('contact_id','contact_first_name','contact_mobile_no','contact_home_no','contact_email','contact_office_no'))
->where('pid = ?', $p_id)
->order('date_created DESC');
return $select;
}
}
after this i simple assign my result to my view.
note please
as its working but there is not private data members in my class,my class is not a blue print.there are no SETTERS AND GETTERS .how can i make my code that best suits MVC and OOP??
The most simple answer: you are already almost MVC. You use a Zend_Controller_Action to grab some data and pass this on to a view layer where you render the html. The only missing part is your model, which is mixed up between the controller and your data gateway (where you implemented a table data gateway pattern, that Zend_Db_Table thing).
I gave a pretty thorough explanation in an answer to another question how I'd properly set up the relations between Controller and Model. I also combined this with a Form, to handle data input, filtering and validation. Then to bundle some common functions, I introduced a Service layer between the Model and Controller.
With the controller, you perform some actions (list all my contacts, create a new contact, modify a contact) and the model is purely containing the data (id, name, phone, address). The service helps to group some functions (findContactByName, findContactById, updateContactWithForm).
If you know how to split Controller, Mode, Form and Service, your controller can become something like this:
class ContactsController extends Zend_Controller_Action
{
public function indexAction ()
{
if (!$this->hasIdentity()) {
$this->_redirect('login/login');
}
$service = new Application_Service_Contacts;
$contacts = $service->getContacts();
$paginator = $service->getPaginator($contacts);
$this->view->paginator = $paginator;
}
protected function hasIdentity ()
{
return Zend_Auth::getInstance->hasIdentity();
}
}
It is your personal taste what you want to do in your controller: I'd say you put as less as possible in your controllers, but you need to keep the control. So: a call to get data happens in the controller, retrieving this data happens somewhere else. Also: a call to convert a dataset into something else happens in the controller, the conversion happens somewhere else.
This way you can change the outcome in controllers extremely fast if you provided enough methods to your service classes to fetch the data. (Note I took the Zend_Auth to another function: if you have other actions, you can use this same function. Also, if you want to change something in your authentication, you have one place where this is located instead of every action in the controller)
keep one thing in mind when u learn new technology so first read thier own documentation. No one can explain better than them. Its hard to understand firstly but when you study it you will usedto and than u will love it like me Zend Offical Site

Asp.net mvc 3- get the current controller instance (not just name)

I know how to get the current controller name
HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
But is there any way to get the current controller instance in some class (not in an action and not in a view)?
By default you can only access the current Controller inside a controller with ControllerContext.Controller or inside a view with ViewContext.Context. To access it from some class you need to implement a custom ControllerFactory which stores the controller instance somewhere and retrieve it from there. E.g in the Request.Items:
public class MyControllerFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controller = base.CreateController(requestContext, controllerName);
HttpContext.Current.Items["controllerInstance"] = controller;
return controller;
}
}
Then you register it in your Application_Start:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
And you can get the controller instance later:
public class SomeClass
{
public SomeClass()
{
var controller = (IController)HttpContext.Current.Items["controllerInstance"];
}
}
But I would find some another way to pass the controller instance to my class instead of this "hacky" workaround.
Someone will have to correct me if what I am doing is detrimental to the whole Asp.Net page life cycle / whatever but surely you can do this:
In controller
ViewBag.CurrentController = this;
In view
var c = ViewBag.CurrentController;
var m1 = BaseController.RenderViewToString(c, "~/Views/Test/_Partial.cshtml", null);
In my case, I had a base controller that all controllers extend. In that base controller lived a static method called RenderViewToString and it required a controller. Since I figured I could just instantiate a new instance of an empty controller at this point for c, I just sent it to the view in the lovely ViewBag container that exists in the world of Asp.Net MVC. For reasons I could not go into now, I could not retrieve the string in the controller and send just that back to the view (this was what I had done earlier before requirements changed).
The reason I have done it this way is in other languages like PHP and JS, there are similar simple ways to transfer classes around.

Resources