Project Student:维护Webapp(可编辑)

这是Project Student的一部分。 其他帖子包括带有Jersey的 Web服务 客户端,带有Jersey的 Web服务服务器 , 业务层 , 具有Spring数据的持久性 ,分片集成测试数据 , Webservice集成 , JPA标准查询和维护Webapp(只读) 。

上一次我们创建了一个简单的Web应用程序,使我们可以快速浏览数据库。 它的功能非常有限-主要目的是将一个系统组合在一起,以行使从Web浏览器到数据库的整个堆栈。 这次我们添加了实际的CRUD支持。

这篇文章是从Jumpstart网站大量借用的,但有很大的不同。 有很多代码,但是很容易重用。

局限性

  • 用户身份验证 –尚未进行身份验证的工作。
  • 加密 –尚未对通信进行加密。
  • 分页 –尚未做出任何努力来支持分页。 Tapestry 5组件将显示分页外观,但始终包含相同的第一页数据。
  • 错误消息 –将显示错误消息,但服务器端错误目前尚无信息。
  • 跨站点脚本(XSS) –尚未做出任何努力来防止XSS攻击。
  • 国际化 –尚未做出任何努力来支持国际化。

目标

我们需要标准的CRUD页面。

首先,我们需要能够创建一门新课程。 当我们没有任何数据时,我们的课程列表应包含一个链接作为默认消息。 (第一个“创建...”是一个单独的元素。)

课程列表Chromium_008

现在,创建页面具有多个字段。 代码唯一地标识一门课程,例如CSCI 101,其名称,摘要和描述应不言自明。

课程编辑器Chromium_006

创建成功后,我们将进入评论页面。

课程编辑器Chromium_002

如果需要进行更改,然后返回更新页面。

课程编辑器Chromium_004

任何时候我们都可以返回列表页面。

课程列表Chromium_001

在删除记录之前,系统会提示我们进行确认。

Course-List-Chromium_005

最后,我们可以显示服务器端错误,例如对于唯一字段中的重复值,即使此刻消息非常无用。

课程编辑器Chromium_007

我们也有客户端错误检查,尽管我在这里没有显示。

Index.tml

我们从索引页面开始。 这与我们在上一篇文章中看到的相似。

Tapestry 5具有三种主要类型的链接。 页面链接被映射到标准HTML链接。 一个ActionLink的是直接由相应的类,例如,Index.javaIndex.tml模板处理。 最后,一个事件链接将一个事件注入到挂毯引擎内的正常事件流中。 我所有的链接都转到一个密切相关的页面,所以我使用一个动作链接。

<html t:type="layout" title="Course List"t:sidebarTitle="Framework Version"xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"xmlns:p="tapestry:parameter"><t:zone t:id="zone">   <p>"Course" page</p><t:actionlink t:id="create">Create...</t:actionlink><br/><t:grid source="courses" row="course" include="code, name,creationdate" add="edit,delete"><p:codecell><t:actionlink t:id="view" context="course.uuid">${course.code}</t:actionlink></p:codecell><p:editcell><t:actionlink t:id="update" context="course.uuid">Edit</t:actionlink></p:editcell><p:deletecell><t:actionlink t:id="delete" context="course.uuid" t:mixins="Confirm" t:message="Delete ${course.name}?">Delete</t:actionlink></p:deletecell><p:empty><p>There are no courses to display; you can <t:actionlink t:id="create1">create</t:actionlink> one.</p></p:empty></t:grid></t:zone><p:sidebar><p>[<t:pagelink page="Index">Index</t:pagelink>]<br/>[<t:pagelink page="Course/Index">Courses</t:pagelink>]</p></p:sidebar></html>

确认混入

Index.tml模板在删除操作链接上包含一个“ mixin”。 它使用javascript和java的混合显示弹出消息,要求用户确认他要删除课程。

该代码直接来自Jumpstart和Tapestry网站。

// from http://jumpstart.doublenegative.com.au/
Confirm = Class.create({initialize: function(elementId, message) {this.message = message;Event.observe($(elementId), 'click', this.doConfirm.bindAsEventListener(this));},doConfirm: function(e) {// Pop up a javascript Confirm Box (see http://www.w3schools.com/js/js_popup.asp)if (!confirm(this.message)) {e.stop();}}
})// Extend the Tapestry.Initializer with a static method that instantiates a Confirm.Tapestry.Initializer.confirm = function(spec) {new Confirm(spec.elementId, spec.message);
}

相应的Java代码是

// from http://jumpstart.doublenegative.com.au/
@Import(library = "confirm.js")
public class Confirm {@Parameter(name = "message", value = "Are you sure?", defaultPrefix = BindingConstants.LITERAL)private String message;@Injectprivate JavaScriptSupport javaScriptSupport;@InjectContainerprivate ClientElement clientElement;@AfterRenderpublic void afterRender() {// Tell the Tapestry.Initializer to do the initializing of a Confirm,// which it will do when the DOM has been// fully loaded.JSONObject spec = new JSONObject();spec.put("elementId", clientElement.getClientId());spec.put("message", message);javaScriptSupport.addInitializerCall("confirm", spec);}
}

Index.java

支持索引模板的Java很简单,因为我们只需要定义一个数据源并提供一些动作处理程序即可。

package com.invariantproperties.sandbox.student.maintenance.web.pages.course;public class Index {@Property@Inject@Symbol(SymbolConstants.TAPESTRY_VERSION)private String tapestryVersion;@InjectComponentprivate Zone zone;@Injectprivate CourseFinderService courseFinderService;@Injectprivate CourseManagerService courseManagerService;@Propertyprivate Course course;// our sibling page@InjectPageprivate com.invariantproperties.sandbox.student.maintenance.web.pages.course.Editor editorPage;/*** Get the datasource containing our data.* * @return*/public GridDataSource getCourses() {return new CoursePagedDataSource(courseFinderService);}/*** Handle a delete request. This could fail, e.g., if the course has already* been deleted.* * @param courseUuid*/void onActionFromDelete(String courseUuid) {courseManagerService.deleteCourse(courseUuid, 0);}/*** Bring up editor page in create mode.* * @param courseUuid* @return*/Object onActionFromCreate() {editorPage.setup(Mode.CREATE, null);return editorPage;}/*** Bring up editor page in create mode.* * @param courseUuid* @return*/Object onActionFromCreate1() {return onActionFromCreate();}/*** Bring up editor page in review mode.* * @param courseUuid* @return*/Object onActionFromView(String courseUuid) {editorPage.setup(Mode.REVIEW, courseUuid);return editorPage;}/*** Bring up editor page in update mode.* * @param courseUuid* @return*/Object onActionFromUpdate(String courseUuid) {editorPage.setup(Mode.UPDATE, courseUuid);return editorPage;}
}

Editor.tml

CRUD页面可以是三个单独的页面(用于创建,查看和更新​​),也可以是一个页面。 我遵循的是Jumpstart网站所使用的模式–一个页面。 老实说-我不确定他为什么做出这个决定-也许是因为页面紧密相关并且他使用事件处理? 无论如何,我将分别讨论这些元素。

创建模板

“创建”模板是一种简单的形式。 您可以看到HTML <input>元素得到了增强,它们具有一些特定于挂毯的属性,以及一些其他标记,例如<t:errors />和<t:submit>。

CustomFormCustomError是标准Tapestry FormError类的本地扩展。 它们目前为空,但允许我们轻松添加本地扩展。

<html t:type="layout" title="Course Editor"t:sidebarTitle="Framework Version"xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter"><t:zone t:id="zone">   <t:if test="modeCreate"><h1>Create</h1><form t:type="form" t:id="createForm" ><t:errors/><table><tr><th><t:label for="code"/>:</th><td><input t:type="TextField" t:id="code" value="course.code" t:validate="required, maxlength=12" size="12"/></td><td>(required)</td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="code"/></td></tr><tr><th><t:label for="name"/>:</th><td><input t:type="TextField" t:id="name" value="course.name" t:validate="required, maxlength=80" size="45"/></td><td>(required)</td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="name"/></td></tr><tr><th><t:label for="summary"/>:</th><td><input cols="50" rows="4" t:type="TextArea" t:id="summary" value="course.summary" t:validate="maxlength=400"/></td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="summary"/></td></tr><tr><th><t:label for="description"/>:</th><td><input cols="50" rows="12" t:type="TextArea" t:id="description" value="course.description" t:validate="maxlength=2000"/></td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="description"/></td></tr></table><div class="buttons"><t:submit t:event="cancelCreate" t:context="course.uuid" value="Cancel"/><input type="submit" value="Save"/></div></form></t:if>...
</html>

创建java

  • 相应的java类很简单。 我们必须定义一些自定义事件。
  • ActivationRequestParameter值是从URL查询字符串中提取的。
  • 课程字段包含创建新对象时要使用的值。
  • courseForm字段在模板上包含相应的<form>。
  • indexPage包含对索引页的引用。

有四个名为onEventFromCreateForm的事件处理程序,其中event
可以准备,验证,成功或失败。 每个事件处理程序都有非常特定的角色。

还有一个附加的事件处理程序onCancelCreate() 。 您可以在模板的<t:submit>标记中看到该事件的名称。

/*** This component will trigger the following events on its container (which in* this example is the page):* {@link Editor.web.components.examples.component.crud.Editor#CANCEL_CREATE} ,* {@link Editor.web.components.examples.component.crud.Editor#SUCCESSFUL_CREATE}* (Long courseUuid),* {@link Editor.web.components.examples.component.crud.Editor#FAILED_CREATE} ,*/
// @Events is applied to a component solely to document what events it may
// trigger. It is not checked at runtime.
@Events({ Editor.CANCEL_CREATE, Editor.SUCCESSFUL_CREATE, Editor.FAILED_CREATE })
public class Editor {public static final String CANCEL_CREATE = "cancelCreate";public static final String SUCCESSFUL_CREATE = "successfulCreate";public static final String FAILED_CREATE = "failedCreate";public enum Mode {CREATE, REVIEW, UPDATE;}// Parameters@ActivationRequestParameter@Propertyprivate Mode mode;@ActivationRequestParameter@Propertyprivate String courseUuid;// Screen fields@Propertyprivate Course course;// Work fields// This carries version through the redirect that follows a server-side// validation failure.@Persist(PersistenceConstants.FLASH)private Integer versionFlash;// Generally useful bits and pieces@Injectprivate CourseFinderService courseFinderService;@Injectprivate CourseManagerService courseManagerService;@Componentprivate CustomForm createForm;@Injectprivate ComponentResources componentResources;@InjectPageprivate com.invariantproperties.sandbox.student.maintenance.web.pages.course.Index indexPage;// The codepublic void setup(Mode mode, String courseUuid) {this.mode = mode;this.courseUuid = courseUuid;}// setupRender() is called by Tapestry right before it starts rendering the// component.void setupRender() {if (mode == Mode.REVIEW) {if (courseUuid == null) {course = null;// Handle null course in the template.} else {if (course == null) {try {course = courseFinderService.findCourseByUuid(courseUuid);} catch (ObjectNotFoundException e) {// Handle null course in the template.}}}}}// /// CREATE// /// Handle event "cancelCreate"Object onCancelCreate() {return indexPage;}// Component "createForm" bubbles up the PREPARE event when it is rendered// or submittedvoid onPrepareFromCreateForm() throws Exception {// Instantiate a Course for the form data to overlay.course = new Course();}// Component "createForm" bubbles up the VALIDATE event when it is submittedvoid onValidateFromCreateForm() {if (createForm.getHasErrors()) {// We get here only if a server-side validator detected an error.return;}try {course = courseManagerService.createCourse(course.getCode(), course.getName(), course.getSummary(),course.getDescription(), 1);} catch (RestClientFailureException e) {createForm.recordError("Internal error on server.");createForm.recordError(e.getMessage());} catch (Exception e) {createForm.recordError(ExceptionUtil.getRootCauseMessage(e));}}// Component "createForm" bubbles up SUCCESS or FAILURE when it is// submitted, depending on whether VALIDATE// records an errorboolean onSuccessFromCreateForm() {componentResources.triggerEvent(SUCCESSFUL_CREATE, new Object[] { course.getUuid() }, null);// We don't want "success" to bubble up, so we return true to say we've// handled it.mode = Mode.REVIEW;courseUuid = course.getUuid();return true;}boolean onFailureFromCreateForm() {// Rather than letting "failure" bubble up which doesn't say what you// were trying to do, we trigger new event// "failedCreate". It will bubble up because we don't have a handler// method for it.componentResources.triggerEvent(FAILED_CREATE, null, null);// We don't want "failure" to bubble up, so we return true to say we've// handled it.return true;}....
}

评论模板

“审阅”模板是一个简单的表。 它以表格形式包装,但仅用于页面底部的导航按钮。

<t:if test="modeReview"><h1>Review</h1><strong>Warning: no attempt is made to block XSS</strong><form t:type="form" t:id="reviewForm"><t:errors/><t:if test="course"><div t:type="if" t:test="deleteMessage" class="error">${deleteMessage}</div><table><tr><th>Uuid:</th><td>${course.uuid}</td></tr><tr><th>Code:</th><td>${course.code}</td></tr><tr><th>Name:</th><td>${course.name}</td></tr><tr><th>Summary:</th><td>${course.summary}</td></tr><tr><th>Description:</th><td>${course.description}</td></tr></table><div class="buttons"><t:submit t:event="toIndex" t:context="course.uuid" value="List"/><t:submit t:event="toUpdate" t:context="course.uuid" value="Update"/><t:submit t:event="delete" t:context="course.uuid" t:mixins="Confirm" t:message="Delete ${course.name}?" value="Delete"/></div></t:if><t:if negate="true" test="course">Course ${courseUuid} does not exist.<br/><br/></t:if></form></t:if>

回顾java

审阅表单所需的Java很简单-我们只需要加载数据即可。 我本来希望setupRender()足够,但实际上我需要onPrepareFromReviewForm()方法。

public class Editor {public enum Mode {CREATE, REVIEW, UPDATE;}// Parameters@ActivationRequestParameter@Propertyprivate Mode mode;@ActivationRequestParameter@Propertyprivate String courseUuid;// Screen fields@Propertyprivate Course course;// Generally useful bits and pieces@Injectprivate CourseFinderService courseFinderService;@Componentprivate CustomForm reviewForm;@Injectprivate ComponentResources componentResources;@InjectPageprivate com.invariantproperties.sandbox.student.maintenance.web.pages.course.Index indexPage;// The codepublic void setup(Mode mode, String courseUuid) {this.mode = mode;this.courseUuid = courseUuid;}// setupRender() is called by Tapestry right before it starts rendering the// component.void setupRender() {if (mode == Mode.REVIEW) {if (courseUuid == null) {course = null;// Handle null course in the template.} else {if (course == null) {try {course = courseFinderService.findCourseByUuid(courseUuid);} catch (ObjectNotFoundException e) {// Handle null course in the template.}}}}}// /// REVIEW// /void onPrepareFromReviewForm() {try {course = courseFinderService.findCourseByUuid(courseUuid);} catch (ObjectNotFoundException e) {// Handle null course in the template.}}// /// PAGE NAVIGATION// /// Handle event "toUpdate"boolean onToUpdate(String courseUuid) {mode = Mode.UPDATE;return false;}// Handle event "toIndex"Object onToIndex() {return indexPage;}....
}

UPDATE模板

最后,“更新”模板看起来类似于“创建”模板。

<t:if test="modeUpdate"><h1>Update</h1><strong>Warning: no attempt is made to block XSS</strong><form t:type="form" t:id="updateForm"><t:errors/><t:if test="course"><!-- If optimistic locking is not needed then comment out this next line. It works because Hidden fields are part of the submit. --><!-- <t:hidden value="course.version"/> --><table><tr><th><t:label for="updCode"/>:</th><td><input t:type="TextField" t:id="updCode" value="course.code" t:disabled="true" size="12"/></td><td>(read-only)</td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="updName"/></td></tr><tr><th><t:label for="updName"/>:</th><td><input t:type="TextField" t:id="updName" value="course.name" t:validate="required, maxlength=80" size="45"/></td><td>(required)</td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="updSummary"/></td></tr><tr><th><t:label for="updSummary"/>:</th><td><input cols="50" rows="4" t:type="TextArea" t:id="updSummary" value="course.summary" t:validate="maxlength=400"/></td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="updSummary"/></td></tr><tr><th><t:label for="updDescription"/>:</th><td><input cols="50" rows="12" t:type="TextArea" t:id="updDescription" value="course.description" t:validate="maxlength=50"/></td></tr><tr class="err"><th></th><td colspan="2"><t:CustomError for="updDescription"/></td></tr></table><div class="buttons"><t:submit t:event="toIndex" t:context="course.uuid" value="List"/><t:submit t:event="cancelUpdate" t:context="course.uuid" value="Cancel"/><input t:type="submit" value="Save"/></div></t:if><t:if negate="true" test="course">Course ${courseUuid} does not exist.<br/><br/></t:if></form>    </t:if>

更新java

同样,“更新” Java代码看起来很像“创建” Java代码。 最大的区别在于,我们必须能够处理在尝试更新数据库之前已删除课程的比赛条件。

@Events({ Editor.TO_UPDATE, Editor.CANCEL_UPDATE,Editor.SUCCESSFUL_UPDATE, Editor.FAILED_UPDATE })
public class Editor {public static final String TO_UPDATE = "toUpdate";public static final String CANCEL_UPDATE = "cancelUpdate";public static final String SUCCESSFUL_UPDATE = "successfulUpdate";public static final String FAILED_UPDATE = "failedUpdate";public enum Mode {CREATE, REVIEW, UPDATE;}// Parameters@ActivationRequestParameter@Propertyprivate Mode mode;@ActivationRequestParameter@Propertyprivate String courseUuid;// Screen fields@Propertyprivate Course course;@Property@Persist(PersistenceConstants.FLASH)private String deleteMessage;// Work fields// This carries version through the redirect that follows a server-side// validation failure.@Persist(PersistenceConstants.FLASH)private Integer versionFlash;// Generally useful bits and pieces@Injectprivate CourseFinderService courseFinderService;@Injectprivate CourseManagerService courseManagerService;@Componentprivate CustomForm updateForm;@Injectprivate ComponentResources componentResources;@InjectPageprivate com.invariantproperties.sandbox.student.maintenance.web.pages.course.Index indexPage;// The codepublic void setup(Mode mode, String courseUuid) {this.mode = mode;this.courseUuid = courseUuid;}// setupRender() is called by Tapestry right before it starts rendering the// component.void setupRender() {if (mode == Mode.REVIEW) {if (courseUuid == null) {course = null;// Handle null course in the template.} else {if (course == null) {try {course = courseFinderService.findCourseByUuid(courseUuid);} catch (ObjectNotFoundException e) {// Handle null course in the template.}}}}}// /// UPDATE// /// Handle event "cancelUpdate"Object onCancelUpdate(String courseUuid) {return indexPage;}// Component "updateForm" bubbles up the PREPARE_FOR_RENDER event during// form rendervoid onPrepareForRenderFromUpdateForm() {try {course = courseFinderService.findCourseByUuid(courseUuid);} catch (ObjectNotFoundException e) {// Handle null course in the template.}// If the form has errors then we're redisplaying after a redirect.// Form will restore your input values but it's up to us to restore// Hidden values.if (updateForm.getHasErrors()) {if (course != null) {course.setVersion(versionFlash);}}}// Component "updateForm" bubbles up the PREPARE_FOR_SUBMIT event during for// submissionvoid onPrepareForSubmitFromUpdateForm() {// Get objects for the form fields to overlay.try {course = courseFinderService.findCourseByUuid(courseUuid);} catch (ObjectNotFoundException e) {course = new Course();updateForm.recordError("Course has been deleted by another process.");}}// Component "updateForm" bubbles up the VALIDATE event when it is submittedvoid onValidateFromUpdateForm() {if (updateForm.getHasErrors()) {// We get here only if a server-side validator detected an error.return;}try {courseManagerService.updateCourse(course, course.getName(), course.getSummary(), course.getDescription(), 1);} catch (RestClientFailureException e) {updateForm.recordError("Internal error on server.");updateForm.recordError(e.getMessage());} catch (Exception e) {// Display the cause. In a real system we would try harder to get a// user-friendly message.updateForm.recordError(ExceptionUtil.getRootCauseMessage(e));}}// Component "updateForm" bubbles up SUCCESS or FAILURE when it is// submitted, depending on whether VALIDATE// records an errorboolean onSuccessFromUpdateForm() {// We want to tell our containing page explicitly what course we've// updated, so we trigger new event// "successfulUpdate" with a parameter. It will bubble up because we// don't have a handler method for it.componentResources.triggerEvent(SUCCESSFUL_UPDATE, new Object[] { courseUuid }, null);// We don't want "success" to bubble up, so we return true to say we've// handled it.mode = Mode.REVIEW;return true;}boolean onFailureFromUpdateForm() {versionFlash = course.getVersion();// Rather than letting "failure" bubble up which doesn't say what you// were trying to do, we trigger new event// "failedUpdate". It will bubble up because we don't have a handler// method for it.componentResources.triggerEvent(FAILED_UPDATE, new Object[] { courseUuid }, null);// We don't want "failure" to bubble up, so we return true to say we've// handled it.return true;}
}

删除模板和Java

编辑器没有明确的“删除”模式,但确实支持删除审阅和更新页面上的当前对象。

// /// DELETE// /// Handle event "delete"Object onDelete(String courseUuid) {this.courseUuid = courseUuid;int courseVersion = 0;try {courseManagerService.deleteCourse(courseUuid, courseVersion);} catch (ObjectNotFoundException e) {// the object's already deleted} catch (RestClientFailureException e) {createForm.recordError("Internal error on server.");createForm.recordError(e.getMessage());// Display the cause. In a real system we would try harder to get a// user-friendly message.deleteMessage = ExceptionUtil.getRootCauseMessage(e);// Trigger new event "failedDelete" which will bubble up.componentResources.triggerEvent(FAILED_DELETE, new Object[] { courseUuid }, null);// We don't want "delete" to bubble up, so we return true to say// we've handled it.return true;} catch (Exception e) {// Display the cause. In a real system we would try harder to get a// user-friendly message.deleteMessage = ExceptionUtil.getRootCauseMessage(e);// Trigger new event "failedDelete" which will bubble up.componentResources.triggerEvent(FAILED_DELETE, new Object[] { courseUuid }, null);// We don't want "delete" to bubble up, so we return true to say// we've handled it.return true;}// Trigger new event "successfulDelete" which will bubble up.componentResources.triggerEvent(SUCCESFUL_DELETE, new Object[] { courseUuid }, null);// We don't want "delete" to bubble up, so we return true to say we've// handled it.return indexPage;}

下一步

显而易见的下一步是改进错误消息,增加对分页,支持以及一对多和多对多关系的支持。 所有这些都需要修改REST负载。 我在管道中还有一些其他项目,例如ExceptionService,更不用说安全问题了。

源代码

  • 可从http://code.google.com/p/invariant-properties-blog/source/browse/student获取源代码。

参考: 项目学生: Invariant Properties博客上的JCG合作伙伴 Bear Giles提供的Maintenance Webapp(可编辑) 。

翻译自: https://www.javacodegeeks.com/2014/02/project-student-maintenance-webapp-editable.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

express接受get数据

server.use(/,function(req,res){res.writeHead(200, { content-type:text/html;charsetutf-8});var namereq.query[name]; //直接req.query[参数名称]&#xff1b;var pwdreq.query[pwd];if(!users[name]){res.write("不存在该用户");}else if(users[name]!pwd){re…

php curl 采集文件,curl获取远程文件内容

/**获取远程文件内容param $url 文件http地址*/function fopen_url($url){if (function_exists(file_get_contents)) {$file_content file_get_contents($url);} elseif (ini_get(allow_url_fopen) && ($file fopen($url, rb))){$i 0;while (!feof($file) &&…

SAP work process Memory allocate

SAP work process Memory allocate Memory allocation sequence to dialog work processes in SAP What is the memory allocation sequence to dialog work processes in SAP?When does a work process go to PRIV mode?How to avoid or minimize work process going to PRI…

基于 Vue.js 的移动端组件库mint-ui实现无限滚动加载更多

通过多次爬坑&#xff0c;发现了这些监听滚动来加载更多的组件的共同点&#xff0c; 因为这些加载更多的方法是绑定在需要加载更多的内容的元素上的&#xff0c; 所以是进入页面则直接触发一次&#xff0c;当监听到滚动事件之后&#xff0c;继续加载更多&#xff0c; 所以对…

创建Maven源代码和Javadoc工件

许多人都知道Maven源代码和Javadoc工件&#xff0c;但是不知道为什么要创建它们。 我肯定在这个阵营中–我可以理解为什么人们想要此信息&#xff0c;但是由于要手动导航Maven存储库&#xff0c;因此获取信息似乎相对效率较低。 然后我被线索棒击中。 这些工件由IDE而非人员使…

JS内置方法(object)

属性 constructorprototype 实例方法 1、toString()返回当前对象的字符串形式&#xff0c;返回值为String类型。 2、toLocaleString()返回当前对象的"本地化"字符串形式&#xff0c;以便于当前环境的用户辨识和使用&#xff0c;返回值为String类型。 3、valueOf()返回…

金蝶云php webapi,K/3 Cloud Web API销售出库单PHP完整示例【分享】

按照惯例&#xff0c;先上图【销售出库单】保存&#xff0c;如图&#xff1a;已经打印出 登陆请求及登陆成功&#xff0c;保存请求及保存成功的返回信息。如下代码&#xff0c;是完全可以直接进行运行的代码&#xff0c;具体详见代码中注释。[code]//K/3 Cloud 业务站点地址$cl…

JavaFX自定义控件– Nest Thermostat第2部分

自从我开始创建Nest恒温器FX自定义控件以来&#xff0c;已经有一段时间了&#xff01; 因此&#xff0c;上次&#xff0c;如Gerrit Grunwald所建议&#xff0c;我花了一些时间用inkscape复制Nest恒温器设计&#xff0c;这是构建JavaFX版本的第一步。 今天&#xff0c;我想与大…

函数和模块的使用

函数&#xff1a; 函数作用&#xff1a; 减少代码重复 增加程序可扩展性 使程序易于维护 函数定义&#xff1a; 关键字&#xff1a;def 名称&#xff1a;与变量名命名规则相同 参数&#xff1a; def fun() #无参数 def fun(x) #普通参数 def fun(name, age22, happyalex) #默…

关于 Error: No PostCSS Config found in 的错误

问题描述&#xff1a; 项目在本地运行不报错&#xff0c;上传到 GitHub 之后&#xff0c;再 clone 到本地&#xff0c; npm install安装完成之后再执行 npm run dev这时报错 Error: No PostCSS Config found in... 本以为是 GitHub 上传的问题&#xff0c;后开又试了两回&am…

haproxy实现会话保持

HAProxy系列文章&#xff1a;http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1.反向代理为什么需要设置cookie 任何一个七层的http负载均衡器&#xff0c;都应该具备一个功能&#xff1a;会话保持。会话保持是保证客户端对动态应用程序正确请求的基本要求。 还是那个被举烂…

java dubbo 方案,Missing artifact com.alibaba:dubbo:jar:2.8.4 dubbo解决方案

由于maven中心仓库中没有dubbo2.8.4&#xff0c;所以需要到github中下载源码包自己编译。下载解压后&#xff0c;进入解压目录执行命令&#xff1a;mvn install -Dmaven.test.skiptrue2.mvn install:install-file -Dfiled:\xxx\dubbo-2.8.4.jar -DgroupIdcom.alibaba -Dartifac…

Java 8:Lambda表达式与自动关闭

如果您通过Neo4j的Java API和Java 6使用了Neo4j的早期版本&#xff0c;则可能具有与以下类似的代码&#xff0c;以确保在事务中进行写操作&#xff1a; public class StylesOfTx {public static void main( String[] args ) throws IOException{String path "/tmp/tx-st…

vue之computed和watch

计算属性 computed 侦听器or观察者 watch 一直以来对computed和watch一知半解&#xff0c;用的时候就迷迷糊糊的&#xff0c;今天仔细看了看文档&#xff0c;突然茅塞顿开&#xff0c;原来就是这么简单啊&#xff1a; computed&#xff0c;通过别人改变自己watch&#xff0c;…

python实现简单的百度翻译

这段时间&#xff0c;一直在学python,想找点东西实现一下&#xff0c;练手&#xff0c;所以我想通过python代码来实现翻译&#xff0c;话不多说&#xff0c;看吧&#xff01; 以chrome为例 1 打开百度翻译 https://fanyi.baidu.com 2 找到请求的url地址 https://fanyi.baidu.…

php不会写 能看懂,人人都能看懂的全栈开发教程——PHP

既然我们是要实现从数据库里读取任务列表这个需求&#xff0c;那么首先我们就得知道如何通过编程的方式从数据库里把数据读出来。这里我们就选 PHP 作为我们的编程语言来实现我们的想法。为什么是 PHP 呢&#xff1f;主要有以下两个原因&#xff1a;PHP 比较简单&#xff0c;入…

与詹金斯一起连续交付Heroku

如果您安装了Jenkins Git插件&#xff0c;那么利用Jenkins并针对Heroku的连续交付管道的设置就非常简单。 通过此管道&#xff0c;对特定Git分支的更改将导致Heroku部署。 为了使此部署过程正常运行&#xff0c;您应该至少使用两个Git分支&#xff0c;因为您希望有一个针对自动…

Goland软件使用教程(二)

Goland软件使用教程&#xff08;二&#xff09;一、编码辅助功能 1. 智能补全 IDE通过自动补全语句来帮助您来编写代码。快捷键“Ctrlshift空格”将会给你一个在当前上下文中最相关符号的列表&#xff0c;当您选择一个建议时&#xff0c;它会相应的将有关包导入到你的当前…

Vue style里面使用@import引入外部css, 作用域是全局的解决方案

问题描述 使用import引入外部css&#xff0c;作用域却是全局的 <template></template><script>export default {name: "user"}; </script><!-- Add "scoped" attribute to limit CSS to this component only --> <styl…

java输出减法表,Calendarjava时间加减法和格式化输出

Calendar calendar Calendar.getInstance();//减三天calendar.add(5, -3);//将Calendar类型转换成Date类型Date tasktimecalendar.getTime();//设置日期输出的格式//六天calendar.add(5, 6);Date tasktime2calendar.getTime();SimpleDateFormat dfnew SimpleDateFormat("…