I have the following controller which accepts an optional "page" parameter.
Right now my URL would look something like mysite.com/pittsburgh-listings?page=2
I want the urls to look like this instead, how can I achieve this?
mysite.com/pittsburgh-listings/2
mysite.com/pittsburgh-listings/3
etc..
My controller
#Controller
public class CityController {
private static final int BUTTONS_TO_SHOW = 5;
private static final int INITIAL_PAGE = 0;
private static final int INITIAL_PAGE_SIZE = 40;
private static final int[] PAGE_SIZES = { 5, 10, 20, 40 };
private AdService adService;
public CityController(AdService adService) {
this.adService = adService;
}
#RequestMapping(value = "/{city:[\\w'-]+}-listings", method = RequestMethod.GET)
public String city(#PathVariable("city") String city, Model model, #RequestParam("page") Optional<Integer> page) {
Database db = new Database();
model.addAttribute("city", city.replace("-", " "));
System.out.println(city.replace("-", " "));
// List<Ad> ads = adService.getPage(1, city.replace("-", " "));
// model.addAttribute("ads", ads);
int evalPageSize = INITIAL_PAGE_SIZE;
int evalPage = (page.orElse(0) < 1) ? INITIAL_PAGE : page.get() - 1;
Long cityId = null;
try {
cityId = db.getCityId(city.replace("-", " "));
} catch (Exception e) {
e.printStackTrace();
}
Page<Ad> ads = adService.findAllPageable(new PageRequest(evalPage, evalPageSize, Sort.Direction.DESC, "id"),
cityId);
System.out.println("Ads: " + ads.getSize());
Pager pager = new Pager(ads.getTotalPages(), ads.getNumber(), BUTTONS_TO_SHOW);
model.addAttribute("ads", ads);
model.addAttribute("selectedPageSize", evalPageSize);
model.addAttribute("pageSizes", PAGE_SIZES);
model.addAttribute("pager", pager);
return "city";
}
}
You can change method signature as follows:
#RequestMapping(value = {"/{city:[\\w'-]+}-listings", "/{city:[\\w'-]+}-listings/{page}"}, method = RequestMethod.GET)
public String city(#PathVariable("city") String city, #PathVariable Optional<Integer> page, Model model) {
// ...
}
In order to map two endpoints (with and without page) in the same controller method and using Java 8 Optional to get page value.
Related
So I have this controller class with some getters and setters and a function:
#Controller
public class Hotels{
public Hotels(String name) {
this.name = name;
}
public Hotels(String name, String price, String longitude, String latitude, String URL, String photoURL) {
this.name = name;
this.price = price;
this.longitude = longitude;
this.latitude = latitude;
this.URL = URL;
PhotoURL = photoURL;
}
public Hotels() {
}
public List<Hotels> returnHotels(String city) throws IOException, InterruptedException {
double[] lnglat = new double[2];
MapController controller = new MapController();
for (int i = 0; i <controller.coolLocations().size(); i++) {
if(controller.coolLocations().get(i).getDescription().equals(city)){
lnglat = controller.coolLocations().get(i).getLnglat();
}
}
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://booking-com.p.rapidapi.com/v1/hotels/search-by-coordinates?order_by=popularity&adults_number=2&units=metric&room_number=1&checkout_date=2022-11-15&filter_by_currency=RON&locale=en-gb&checkin_date=2022-11-12&latitude="+lnglat[1]+"&longitude="+lnglat[0]))
.header("X-RapidAPI-Key", "myKey")
.header("X-RapidAPI-Host", "booking-com.p.rapidapi.com")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
String[] datasplit = response.body().split("\"");
String url = "";
String hotel_name = "";
String latitude = "";
String longitude = "";
String gross_price= "";
String main_photo_url= "";
for (int i = 0; i < datasplit.length; i++) {
if (datasplit[i].equals("url")) url = datasplit[i+2];
if (datasplit[i].equals("hotel_name")) hotel_name = datasplit[i+2];
if (datasplit[i].equals("latitude")) latitude = datasplit[i+1].substring(1).replace(',',' ');
if (datasplit[i].equals("longitude")) longitude = datasplit[i+1].substring(1).replace(',',' ');
if ((datasplit[i].equals("gross_amount_hotel_currency") && datasplit[i+1].equals(":{") && datasplit[i+2].equals("value"))) gross_price = datasplit[i+3].substring(1).replace('}',' ').replace(',',' ');
if ((datasplit[i].equals("gross_amount_hotel_currency") && datasplit[i+1].equals(":{") && datasplit[i+2].equals("currency") && datasplit[i+3].equals(":") && datasplit[i+4].equals("EUR")&& datasplit[i+5].equals(",") && datasplit[i+6].equals("value"))) gross_price = datasplit[i+7].substring(1).replace('}',' ').replace(',',' ');
if (datasplit[i].equals("max_photo_url")) main_photo_url = datasplit[i+2];
if(datasplit[i].equals("max_1440_photo_url"))hotelsList.add(new Hotels(hotel_name, gross_price, longitude, latitude, url, main_photo_url));
}
hotelsList.forEach(System.out::println);
System.out.println(city);
return hotelsList;
}
}
And this is my get Mapping :
#GetMapping("/")
public String homePage(Model model) throws IOException, InterruptedException {
model.addAttribute("returnHotels", new Hotels());
return "home";
}
And a JavaScript on click listener :
marker.getElement().addEventListener('click', function () {
const city = location.description;
});
I want inside the JS click listener to call my returnHotels function with the const city as my parameter. Is it possible?
PS : I've deleted the class variables so the site let me post
I am currently working on JAVA FX application to fetch the user's information from JIRA REST API. I want to have a refresh button and on clicking it,the table view must be shown with the newly added data.
Please have a look at the code.
My POJO class
public class Issues {
private String jiraKey;
private String jiraSummary;
private String jiraPriority;
private String jiraAssignee;
private String jiraIssueType;
private Hyperlink hyperLink;
private String loghours;
private String commentLogHours;
public Issues(String jiraKey, String jiraSummary, String jiraPriority, String jiraAssignee, String jiraIssueType) {
super();
this.hyperLink = new Hyperlink(jiraKey);
this.jiraSummary = jiraSummary;
this.jiraPriority = jiraPriority;
this.jiraAssignee = jiraAssignee;
this.jiraIssueType = jiraIssueType;
this.hyperLink = hyperLink;
this.loghours = loghours;
this.commentLogHours = commentLogHours;
}
public String getJiraKey() {
return jiraKey;
}
public void setJiraKey(String jiraKey) {
this.jiraKey = jiraKey;
}
//getters and setters
}
My Observable list method which populates the data to table
Class ABC{
public ObservableList<Issues> issueJsonList(){
// A processed arraylist
ObservableList<Issues> data = FXCollections.observableList(list);
return data;
}
}
Here's my tableview code.
#SuppressWarnings({ "unchecked", "rawtypes" })
public TableView<Issues> initTable() throws IOException, URISyntaxException {
TableView<Issues> table = new TableView<Issues>();
table.setEditable(true);
TableColumn<Issues, Hyperlink> jiraKey = new TableColumn<>(keyField);
jiraKey.setCellValueFactory(new PropertyValueFactory("hyperLink"));
jiraKey.setCellFactory(new HyperlinkCell());
TableColumn jiraPriority = new TableColumn(priorityField);
TableColumn jiraIssueType = new TableColumn(issueTypeField);
TableColumn jiraSummary = new TableColumn(summaryField);
TableColumn jiraAssignee = new TableColumn(assigneeField);
TableColumn workLogCol = new TableColumn(workLogField);
TableColumn timeSpent = new TableColumn(timeSpentField);
TableColumn commentTimeLog = new TableColumn(commentField);
workLogCol.getColumns().addAll(timeSpent, commentTimeLog);
jiraSummary.setCellValueFactory(new PropertyValueFactory("jiraSummary"));
jiraIssueType.setCellValueFactory(new PropertyValueFactory("jiraIssueType"));
jiraPriority.setCellValueFactory(new PropertyValueFactory("jiraPriority"));
jiraAssignee.setCellValueFactory(new PropertyValueFactory("jiraAssignee"));
timeSpent.setCellValueFactory(new PropertyValueFactory("getTimeSpent"));
timeSpent.setCellFactory(TextFieldTableCell.forTableColumn());
commentTimeLog.setCellValueFactory(new PropertyValueFactory("getComment"));
commentTimeLog.setCellFactory(TextFieldTableCell.forTableColumn());
timeSpent.setOnEditCommit(new EventHandler<CellEditEvent<JiraAuth, String>>() {
public void handle(CellEditEvent<JiraAuth, String> t) {
JiraAuth.setTimeSpent(t.getNewValue());
}
});
commentTimeLog.setCellFactory(TextFieldTableCell.forTableColumn());
commentTimeLog.setOnEditCommit(new EventHandler<CellEditEvent<JiraAuth, String>>() {
public void handle(CellEditEvent<JiraAuth, String> t) {
JiraAuth.setWorkLogComment(t.getNewValue());
int i = t.getTablePosition().getRow();
String abc = table.getColumns().get(0).getCellData(i).toString();
String finalStr = abc.substring(abc.indexOf("]") + 1);
JiraAuth.setWorkLogJiraKey(finalStr);
}
});
table.getColumns().setAll(jiraKey, jiraSummary, jiraPriority, jiraAssignee, jiraIssueType);
IssuesJsonParser issueObject = new IssuesJsonParser();
ObservableList<Issues> data = issueObject.issueJsonList();
table.setItems(data);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
return table;
}
upon calling the refresh button,
buttons[0] = new Button("Refresh");
buttons[0].setOnAction(event->{
initTable().refresh();
});
nothing happens. Please help!!
I want to log all the request headers. I already have a filter like so.
Now how do I get all the request header so that I can log them?
public class LogApiFilter : AbstractActionFilter
{
private readonly ILog m_Log;
public override bool AllowMultiple
{
get
{
return true;
}
}
public LogApiFilter(ILog iLog)
{
if (iLog == null)
throw new ArgumentNullException("log instance injected is null.");
m_Log = iLog;
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
}
public override void OnActionExecuting(HttpActionContext context)
{
m_Log.Debug("Web api Controller Name and Action method Name: "
+ context.ActionDescriptor.ControllerDescriptor.ControllerName
+ ", " + context.ActionDescriptor.ActionName);
base.OnActionExecuting(context);
}
}
Ok, for my own records and for others, I have comeup with this. Please do suggest if there is a better way.
private string GetRequestHeaders(HttpActionContext context)
{
// Note you can replace the type names sucha as string, HttpRequestHeaders, List<KeyValuePair<string, IEnumerable<string>>>
// with var keyword where ever possible for readability.
string headerString = string.Empty;
HttpRequestHeaders requestHeaders = context.Request.Headers;
List<KeyValuePair<string, IEnumerable<string>>> headerList = requestHeaders.ToList();
foreach (var header in headerList)
{
string key = header.Key;
List<string> valueList = header.Value.ToList();
string valueString = string.Empty;
foreach (var v in valueList)
{
valueString = valueString + v + "-";
}
headerString = headerString + key + ": " + valueString + Environment.NewLine;
}
return headerString;
}
The above method can be called from the action filter in the question. I am calling it from the method, OnActionExecuting(HttpActionContext context).
I am using ninject for di, so this is how I have configured it.
kernel.BindHttpFilter<LogApiFilter>(System.Web.Http.Filters.FilterScope.Global);
kernel.BindHttpFilter<ApiExceptionFilterAttribute>(System.Web.Http.Filters.FilterScope.Global);
kernel.BindFilter<LogMvcFilter>(System.Web.Mvc.FilterScope.Global, 0);
can anyone shall explain how to load regionCoprocessor trough shell.i can not getting proper information about loading and deploying Coprocessor.Thanks in Advance
Please follow the steps below:
Step 1: Create an interface and extend org.apache.hadoop.hbase.ipc.CoprocessorProtocol
Step 2: Define the method in the interface you want to execute once the co-processor call is made
Step 3: Create an instance of HTable
Step 4: Call the HTable.coprocessorExec() method with all required parameters
Please find the example below:
In the example, we are trying to get list of students whose registration number falls within some range which we are interested in.
Creating Interface Protocol:
public interface CoprocessorTestProtocol extends org.apache.hadoop.hbase.ipc.CoprocessorProtocol{
List<Student> getStudentList(byte[] startRegistrationNumber, byte[] endRegistrationNumber) throws IOException;
}
Sample Student Class:
public class Student implements Serializable{
byte[] registrationNumber;
String name;
public void setRegistrationNumber(byte[] registrationNumber){
this.registrationNumber = registrationNumber;
}
public byte[] getRegistrationNumber(){
return this.registrationNumber;
}
public void setName(String name){
this.name = name;
}
public int getName(){
return this.name;
}
public String toString(){
return "Student[ registration number = " + Bytes.toInt(this.getRegistrationNumber()) + " name = " + this.getName() + " ]"
}
}
Model Class: [Where the business logic to get data from HBase is written]
public class MyModel extends org.apache.hadoop.hbase.coprocessor.BaseEndpointCoprocessor implements CoprocessorTestProtocol{
#Override
List<Student> getStudentList(byte[] startRegistrationNumber, byte[] endRegistrationNumber){
Scan scan = new Scan();
scan.setStartRow(startRegistrationNumber);
scan.setStopRow(endRegistrationNumber);
InternalScanner scanner = ((RegionCoprocessorEnvironment) getEnvironment()).getRegion().getScanner(scan);
List<KeyValue> currentTempObj = new ArrayList<KeyValue>();
List<Student> studentList = new ArrayList<Student>();
try{
Boolean hasNext = false;
Student student;
do{
currentTempObj.clear();
hasNext = scanner.next(currentTempObj);
if(!currentTempObj.isEmpty()){
student = new Student();
for(KeyValue keyValue: currentTempObj){
bytes[] qualifier = keyValue.getQualifier();
if(Arrays.equals(qualifier, Bytes.toBytes("registrationNumber")))
student.setRegistrationNumber(keyValue.getValue());
else if(Arrays.equals(qualifier, Bytes.toBytes("name")))
student.setName(Bytes.toString(keyValue.getValue()));
}
StudentList.add(student);
}
}while(hasNext);
}catch (Exception e){
// catch the exception the way you want
}
finally{
scanner.close();
}
}
}
Client class: [where the call to co-processor is made]
public class MyClient{
if (args.length < 2) {
System.out.println("Usage : startRegistrationNumber endRegistrationNumber");
return;
}
public List<Student> displayStudentInfo(int startRegistrationNumber, int endRegistrationNumber){
final byte[] startKey=Bytes.toBytes(startRegistrationNumber);
final byte[] endKey=Bytes.toBytes(endRegistrationNumber);
String zkPeers = SystemInfo.getHBaseZkConnectString();
Configuration configuration=HBaseConfiguration.create();
configuration.set(HConstants.ZOOKEEPER_QUORUM, zkPeers);
HTableInterface table = new HTable(configuration, TABLE_NAME);
Map<byte[],List<Student>> allRegionOutput;
allRegionOutput = table.coprocessorExec(CoprocessorTestProtocol.class, startKey,endKey,
new Batch.Call<CoprocessorTestProtocol, List<Student>>() {
public List<Student> call(CoprocessorTestProtocol instance)throws IOException{
return instance.getStudentList(startKey, endKey);
}
});
table.close();
List<Student> anotherList = new ArrayList<Student>();
for (List<Student> studentData: allRegionOutput.values()){
anotherList.addAll(studentData);
}
return anotherList;
}
public static void main(String args){
if (args.length < 2) {
System.out.println("Usage : startRegistrationNumber endRegistrationNumber");
return;
}
int startRegistrationNumber = args[0];
int endRegistrationNumber = args[1];
for (Student student : displayStudentInfo(startRegistrationNumber, endRegistrationNumber)){
System.out.println(student);
}
}
}
Please Note: Please have a special look on Scanner.next(Object) method in the example. This returns boolean and stores the current object in Object argument
I am using Query DSL and want my result set to return a Page Object. Is there a way to do that in Query DSL? If so Whats my query going to be looking like?
I am using JPAQuery and I have my QClasses
The Method structure is this
public Page<Object> searchPerson(String name,String phone){
Page<Object> results=null;
JPQLQuery query = new JPAQuery(entityManager);
QPerson person = QPerson.person;
//I am assuming my query would go here
results = query.from(person). ?????
return results;}
Help!
Here is my implementation for Paging with QueryDSL. A PageRequest defines the parameters for our query (limit and page):
public class PageRequest {
protected Long page = 1l;// 1 is the first page
protected Integer limit = 10;
public PageRequest(Long page, Integer limit) {
this.limit = limit;
this.page = page;
}
public Long getPage() {
return page;
}
public Integer getLimit() {
return limit;
}
public Long getOffset() {
return (page - 1l) * limit;
}
}
The Page Class contains the result (here the attribute objects) of the query and could implement methods to create nice paging links.
public class Page<T> extends PageRequest {
protected Collection<T> objects;
private Long totalCount;
private Long pageCount;
private Boolean hasPageLinkPrev;
private Boolean hasPageLinkNext;
private Collection<Long> pageLinks;
public Page(Long page, Integer limit, Long totalCount, Collection<T> objects) {
this.page = page;
this.limit = limit;
this.totalCount = totalCount;
this.objects = objects;
this.pageCount = totalCount / limit;
if (totalCount % limit > 0) {
this.pageCount = this.pageCount + 1;
}
this.hasPageLinkPrev = page > 1;
this.hasPageLinkNext = page < this.pageCount;
this.pageLinks = new ArrayList<>();
if (this.pageCount != 1) {
this.pageLinks.add(1l);
if (page > 3l) {
this.pageLinks.add(-1l);
}
if (page > 2l) {
if (page.equals(this.pageCount) && this.pageCount > 3l) {
this.pageLinks.add(page - 2l);
}
this.pageLinks.add(page - 1l);
}
if (page != 1l && !page.equals(this.pageCount)) {
this.pageLinks.add(page);
}
if (page < this.pageCount - 1l) {
this.pageLinks.add(page + 1l);
if (page == 1l && this.pageCount > 3l) {
this.pageLinks.add(page + 2l);
}
}
if (page < this.pageCount - 2l) {
this.pageLinks.add(-1l);
}
this.pageLinks.add(this.pageCount);
}
}
public Page(PageRequest pageRequest, Long totalCount, Collection<T> objects) {
this(pageRequest.getPage(), pageRequest.getLimit(), totalCount, objects);
}
public Long getTotalCount() {
return this.totalCount;
}
public Long getPageCount() {
return this.pageCount;
}
public Long getPage() {
return this.page;
}
public Integer getLimit() {
return this.limit;
}
public Boolean getHasPageLinkPrev() {
return this.hasPageLinkPrev;
}
public Boolean getHasPageLinkNext() {
return hasPageLinkNext;
}
public Collection<Long> getPageLinks() {
return pageLinks;
}
public Collection<T> getObjects() {
return objects;
}
}
With that stuf it is not very hard to create the query and put the results in our page object. One possibility is to write a generic method in the base class of the repository classes:
protected <T> Page<T> getPage(JPQLQuery<T> query, PageRequest pageRequest) {
List<T> resultList = query
.offset(pageRequest.getOffset())
.limit(pageRequest.getLimit())
.fetch();
Long totalCount = query.fetchCount();
return new Page<T>(pageRequest, totalCount, resultList);
}
In your repository class you create your query for the particular use case. Then you can use the method getPage to get the results in a Page.
public Page<Person> searchPerson(String name,
String phone,
PageRequest request){
Page<Person> results=null;
JPQLQuery<Person> query = new JPAQuery<>(entityManager);
QPerson person = QPerson.person;
query = query.from(person)
.where(person.name.eq(name)
.and(person.phone.eq(phone)));
return getPage(query, request);
}
The solution for the above was using BooleanBuilder implemented on the method above and changed the method name to return Person Object.
Please check BooleanBuilder
QPerson person= QPerson.person;
BooleanBuilder builder = this.getBuilder(name, phone,page, pageSize, sortFlag, sortItem);
PageRequest pg = getPRequest(page, pageSize);
Page<Person> pages personRepo.findAll(builder,pg);
return pages;
and then Implemented getBuilder Method for it which is the below one
public BooleanBuilder getBuilder(String name, String phone, Integer page, Integer pageSize, String sortFlag, String sortItem) {
QPerson person = QPerson.person;
BooleanBuilder builder = new BooleanBuilder();
builder.and(person.name.startsWith(name));
return builder;
}
and finally implemented the getPRequest Method as the following
public PageRequest getPRequest(Integer page, Integer pageSize) {
return new PageRequest(page, pageSize);
}
Oooooh Happy Days!